Vai al contenuto
animorio
EN
Tutti i componenti

Il foglio dal basso

Finestre, Fisica, TransizioniGSAPImpegnativaPeso compresso: Demo 7,3 KBGSAP 28 KBGratisScarica lo zip

Un foglio che sale dal fondo dello schermo e si ferma a metà: si trascina col dito, oltre la cima si allunga come gomma e, lasciato, sceglie dove fermarsi da dove si trova e da quanto veloce andava; lanciato in giù si chiude.

Il codice

Una cartella che funziona da sola: index.html, style.css, script.js e le librerie da CDN. Nelle schede React e Vue la stessa demo è già un componente, che spegne le sue animazioni quando esce dalla pagina.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The bottom sheet</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/plus-jakarta-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <button class="open" type="button" aria-haspopup="dialog" data-open data-autoclic>
      <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 15V4.5M7.5 8.5 12 4l4.5 4.5M5 12.5v5.5a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-5.5"/></svg>
      <span>Share</span>
    </button>
  </main>

  <!-- the sheet: a real dialog (focus kept inside, Escape, the page behind out of reach) whose panel rises from the
       bottom. It can be dragged: it stops at half height or at full height, stretches a little past the top and
       closes when thrown down. The script moves it with a spring -->
  <dialog class="sheet" aria-labelledby="sheet-title" data-sheet>
    <div class="sheet__shade" data-shade></div>
    <div class="sheet__panel" tabindex="-1" data-panel>
      <button class="sheet__grab" type="button" aria-label="Show more" data-grab><span></span></button>
      <div class="sheet__head">
        <div>
          <h2 class="sheet__title" id="sheet-title">Share this stay</h2>
          <p class="sheet__sub">Two nights in the hills, from 14 November</p>
        </div>
        <button class="sheet__close" type="button" aria-label="Close" data-close>
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 7l10 10M17 7 7 17"/></svg>
        </button>
      </div>
      <div class="sheet__apps" data-half>
        <button class="app" type="button" data-copy>
          <span class="app__ring"><svg viewBox="0 0 24 24" aria-hidden="true" data-copy-icon><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1.2 1.2M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1.2-1.2"/></svg></span>
          <span class="app__name" data-copy-label>Copy link</span>
        </button>
        <button class="app" type="button" data-action>
          <span class="app__ring"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4.5 18.5V7a2.5 2.5 0 0 1 2.5-2.5h10A2.5 2.5 0 0 1 19.5 7v7a2.5 2.5 0 0 1-2.5 2.5H8.5z"/></svg></span>
          <span class="app__name">Message</span>
        </button>
        <button class="app" type="button" data-action>
          <span class="app__ring"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6.5h16v11H4zM4.5 7l7.5 6 7.5-6"/></svg></span>
          <span class="app__name">E-mail</span>
        </button>
        <button class="app" type="button" data-action>
          <span class="app__ring"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h5v5H5zM14 5h5v5h-5zM5 14h5v5H5zM14 14h5v5h-5z"/></svg></span>
          <span class="app__name">More</span>
        </button>
      </div>
      <ul class="sheet__rows">
        <li><button class="row" type="button" data-action><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 4.5h10v15l-5-3.5-5 3.5z"/></svg>Add to a list</button></li>
        <li><button class="row" type="button" data-action><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 3.5h7l4 4v13H7zM14 3.5v4h4M9.5 13h6M9.5 16.5h6"/></svg>Save as PDF</button></li>
        <li><button class="row" type="button" data-action><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 9V4h9v5M7.5 17H5v-6.5a1.5 1.5 0 0 1 1.5-1.5h11a1.5 1.5 0 0 1 1.5 1.5V17h-2.5M7.5 14h9v6h-9z"/></svg>Print</button></li>
        <li><button class="row" type="button" data-action><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4.5 4.5h6v6h-6zM13.5 4.5h6v6h-6zM4.5 13.5h6v6h-6zM14 14h2.5v2.5H14zM17 17h2.5v2.5H17z"/></svg>Show a QR code</button></li>
        <li><button class="row row--quiet" type="button" data-action><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5.5 20V4.5M5.5 5h11l-2 4 2 4h-11"/></svg>Report a problem</button></li>
      </ul>
    </div>
  </dialog>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Cambia valori, colori e testi con le manopole e guarda l’animazione rispondere dal vivo. Oppure scrivi tu nel codice. Poi scarica la cartella con le tue modifiche.

25 valori da cambiare

Oppure chiedila a Claude Code

Col connettore di Animorio, Claude Code la prende da qui con tutta la sua guida e la adatta al tuo progetto. Incolla questa richiesta:

Prendi «Il foglio dal basso» da Animorio e adattala al mio sito

Cosa fa

Su un fondo bianco un pulsante nero Share. Premendolo la pagina si scurisce, il pulsante arretra un poco e dal fondo sale un foglio bianco arrotondato in alto, che si ferma a metà: una linguetta grigia, Share this stay con sotto Two nights in the hills, from 14 November e una crocetta, poi quattro pulsanti tondi che spuntano uno dopo l’altro (Copy link, Message, E-mail, More) e l’inizio della prima riga. Il foglio si trascina da qualsiasi punto: segue il dito, oltre la cima si allunga sempre meno, come gomma, e la linguetta si allarga; lasciato, va a metà o in cima secondo dove si trova e quanto veloce andava, e lanciato in giù si chiude. In cima si vedono anche le righe Add to a list, Save as PDF, Print, Show a QR code e, in rosso, Report a problem. La linguetta è un pulsante che mostra di più o di meno; Esc, la crocetta o un tocco sulla pagina scura chiudono il foglio, che scende mentre la pagina si schiarisce. Copy link copia l’indirizzo e per un momento diventa blu, con una spunta e la scritta Copied; gli altri pulsanti chiudono il foglio.

Come funziona

Un dialog vero

Il foglio sta in un dialog aperto con showModal(): il fuoco resta dentro (lo script lo porta sul pannello, da dove Tab raggiunge i pulsanti), Esc lo chiude e la pagina dietro non si raggiunge. Il dialog occupa tutto lo schermo ed è trasparente; dentro ci sono l’ombra scura e il pannello. L’evento cancel viene fermato e il foglio si chiude da sé a fine discesa.

Una molla sola

Il pannello ha una sola posizione, y, contata dalla cima, e una molla con rigidità e smorzamento di SPRING che lo porta al punto scelto, calcolata sul ticker di GSAP a passi di 4 millisecondi. A ogni fotogramma l’ombra e il pulsante che arretra (SINK) seguono quanto foglio si vede.

Il trascinamento

Premere sul pannello lo ferma sotto il dito; dopo 6 pixel di movimento è un trascinamento e il puntatore viene catturato. Oltre la cima il pannello va avanti come STRETCH · (1 − 1/(0,55 · oltre/STRETCH + 1)), sempre meno e mai più di STRETCH; e per non lasciare vuoti sotto di sé continua 160 pixel oltre il bordo dello schermo.

Dove fermarsi

Lasciato, la velocità viene dagli ultimi 90 millisecondi del trascinamento: lo script guarda dove sarebbe il pannello dopo THROW secondi a quella velocità e sceglie la fermata più vicina fra cima, metà e chiuso. La molla parte con la velocità del lancio, così il gesto continua nell’arrivo.

L’anteprima della libreria

L’anteprima clicca un solo segno, data-autoclic, che lo script sposta: prima su Share, a foglio aperto sulla linguetta (che lo porta in cima), in cima sulla crocetta. Così l’anteprima apre, allarga e chiude da sola, sempre da capo.

Valori da cambiare

NomeFileDi partenzaCosa cambia
SPRINGscript.js[420, 0.86]La molla del pannello: quanto è rigida e quanto è frenata (1 = senza rimbalzi).
THROWscript.js0.18Quanto conta un lancio nello scegliere dove fermarsi, in secondi della sua velocità.
STRETCHscript.js110Quanto si può allungare il pannello oltre la cima, al massimo, in pixel.
SHADEscript.js1Quanto si scurisce la pagina dietro il pannello, da 0 a 1.
SINKscript.js0.06Quanto arretra il pulsante Share mentre il foglio è aperto.
PEEKscript.js30Quanto si vede, a metà altezza, di quello che viene dopo i pulsanti tondi, in pixel.

Provali nel Playground

Quando usarla

Per condividere, per i filtri di una ricerca, per le opzioni di un elemento, per un carrello o un riepilogo: soprattutto al telefono, dove il pollice arriva comodo in fondo allo schermo.

Sul telefono

Al telefono il foglio prende tutta la larghezza e lascia spazio alla barra in fondo dell’iPhone; si trascina col dito da qualsiasi punto, e due tocchi veloci non ingrandiscono la pagina. Se il contenuto è più alto dello schermo il foglio scorre col dito e si trascina solo dalla linguetta e dal titolo.

Con il movimento ridotto

Il foglio compare e sparisce con una dissolvenza veloce invece di salire e scendere, passa da metà alla cima senza movimento e i pulsanti tondi non spuntano; trascinato, segue comunque il dito.

Trappole

  • Il dialog nativo aperto con showModal tiene il fuoco dentro, chiude con Esc e rende irraggiungibile la pagina dietro, ma si chiude di colpo: lo script ferma l’evento cancel e chiude il dialog da sé quando il foglio è sceso.
  • Allungato oltre la cima, il foglio lascerebbe un vuoto sotto di sé: per questo continua 160 pixel sotto il bordo dello schermo, col suo bianco.
  • Un trascinamento che finisce sopra un pulsante non deve premerlo: dopo 6 pixel lo script cattura il puntatore e per un attimo ferma il clic che segue.
  • Il fuoco iniziale va sul pannello (tabindex −1, senza contorno) e ce lo porta lo script: sul dialog intero il contorno girerebbe intorno a tutto lo schermo, un pulsante preso da script in Safari mostrerebbe il suo contorno anche dopo un tocco, e l’attributo autofocus dentro una pagina incorniciata da un altro sito verrebbe bloccato.
  • Il pannello ha touch-action: none, così il dito lo trascina invece di scorrere la pagina; se il contenuto è più alto dello schermo torna a scorrere, e lo si trascina solo dall’alto.
  • Il dialog va chiuso al suo contenuto con overflow: clip e non hidden: un riquadro hidden si lascia ancora scorrere, e aprendo il dialog Safari lo farebbe scorrere per mostrare il primo pulsante, che in quel momento è ancora sotto lo schermo.
  • Chiuso il foglio il fuoco torna su Share, ma dopo un tocco Safari ne mostrerebbe il contorno: lo script ricorda se l’ultimo gesto è stato del dito, del mouse o dei tasti, e il contorno si vede solo coi tasti.

Librerie

GSAP 3.15.0, Plus Jakarta Sans (font variabile) 5.3.0.

Compressi con gzip, i tre file della demo pesano 7,3 KB; le librerie: GSAP 28 KB.

Collaudo

Provata il 3 ottobre 2026

  • Computer: Fatto
  • Telefono: Fatto
  • Movimento ridotto: Fatto
  • Safari su iPhone: Fatto

Licenza d’uso

Puoi usarla nei tuoi progetti e in quelli dei tuoi clienti. Non puoi rivenderla né ridistribuirla così com’è. GSAP resta sotto la sua licenza Standard. Licenza completa.

Tutti i componenti