Vai al contenuto
animorio
EN
Tutti i componenti

La tendina che cambia forma

Menu, Hover, TransizioniGSAPImpegnativaPeso compresso: Demo 6,3 KBGSAP 28 KBGratisScarica lo zip

Una barra con tre menu che condividono un pannello solo: passando da un menu all’altro il pannello cambia larghezza, altezza e posto, la sua freccetta scivola sotto il nuovo pulsante e le liste scorrono dal lato da cui arrivano, sempre tagliate dentro il pannello.

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 dropdown that changes shape</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">
    <div class="zone" data-zone>
      <!-- one panel for every menu: moving from one to the next it changes size and place, and the contents slide in
           from the side they come from. Each list sits in the page right after its button, for the Tab key -->
      <nav class="nav" aria-label="Main" data-nav>
        <ul class="nav__list">
          <li>
            <button class="nav__trigger" type="button" aria-expanded="false" aria-controls="drop-products" data-trigger data-autoclic>Products<svg class="nav__caret" viewBox="0 0 14 14" aria-hidden="true"><path d="M3.5 5.5 7 9l3.5-3.5"/></svg></button>
            <div class="drop drop--products" id="drop-products" data-section>
              <ul class="drop__list">
                <li><a class="drop__link" href="#"><span class="drop__icon" style="--tint: #ece8ff; --mark: #6246ea"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 19V11M12 19V5M19 19v-5"/></svg></span><span class="drop__text"><b>Analytics</b><small>See what happens on your site</small></span></a></li>
                <li><a class="drop__link" href="#"><span class="drop__icon" style="--tint: #dff6ec; --mark: #138a5a"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M17 3l3 3-3 3M20 6H9a5 5 0 0 0-5 5M7 21l-3-3 3-3M4 18h11a5 5 0 0 0 5-5"/></svg></span><span class="drop__text"><b>Automations</b><small>Let the routine run by itself</small></span></a></li>
                <li><a class="drop__link" href="#"><span class="drop__icon" style="--tint: #ffeedd; --mark: #d0611b"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 3h7l4 4v14H7zM14 3v4h4M10 12h5M10 16h5"/></svg></span><span class="drop__text"><b>Reports</b><small>Numbers your team can read</small></span></a></li>
              </ul>
            </div>
          </li>
          <li>
            <button class="nav__trigger" type="button" aria-expanded="false" aria-controls="drop-solutions" data-trigger data-autoclic>Solutions<svg class="nav__caret" viewBox="0 0 14 14" aria-hidden="true"><path d="M3.5 5.5 7 9l3.5-3.5"/></svg></button>
            <div class="drop drop--solutions" id="drop-solutions" data-section>
              <div class="drop__column">
                <p class="drop__heading">By size</p>
                <a class="drop__plain" href="#">Startups</a>
                <a class="drop__plain" href="#">Agencies</a>
                <a class="drop__plain" href="#">Enterprise</a>
              </div>
              <div class="drop__column">
                <p class="drop__heading">By field</p>
                <a class="drop__plain" href="#">Retail</a>
                <a class="drop__plain" href="#">Education</a>
                <a class="drop__plain" href="#">Nonprofits</a>
              </div>
            </div>
          </li>
          <li>
            <button class="nav__trigger" type="button" aria-expanded="false" aria-controls="drop-developers" data-trigger data-autoclic>Developers<svg class="nav__caret" viewBox="0 0 14 14" aria-hidden="true"><path d="M3.5 5.5 7 9l3.5-3.5"/></svg></button>
            <div class="drop drop--developers" id="drop-developers" data-section>
              <a class="drop__card" href="#">
                <svg class="drop__glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M8 8l-4 4 4 4M16 8l4 4-4 4M13.5 5l-3 14"/></svg>
                <b>Read the docs</b>
                <small>Everything you need to build with us, from the first call to the last.</small>
              </a>
              <ul class="drop__list drop__list--small">
                <li><a class="drop__link drop__link--small" href="#"><span class="drop__mini"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h10"/></svg></span><b>API reference</b></a></li>
                <li><a class="drop__link drop__link--small" href="#"><span class="drop__mini"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 4h10l4 4v12H5zM9 12h6M9 16h4"/></svg></span><b>Guides</b></a></li>
                <li><a class="drop__link drop__link--small" href="#"><span class="drop__mini"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 7v5l3 2M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z"/></svg></span><b>Changelog</b></a></li>
                <li><a class="drop__link drop__link--small" href="#"><span class="drop__mini"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 12h4l3-7 4 14 3-7h4"/></svg></span><b>Status</b></a></li>
              </ul>
            </div>
          </li>
          <li><a class="nav__trigger nav__trigger--link" href="#">Pricing</a></li>
        </ul>
        <!-- the white panel behind the lists, and its little arrow: they move, the lists take turns on top -->
        <span class="panel" data-panel aria-hidden="true"></span>
        <span class="arrow" data-arrow aria-hidden="true"></span>
      </nav>
    </div>
  </main>

  <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.

40 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 «La tendina che cambia forma» da Animorio e adattala al mio sito

Cosa fa

Una barra su un fondo bianco con tre menu, Products, Solutions e Developers, e un link, Pricing. I tre menu condividono un pannello bianco: puntando un pulsante la sua lista si apre sotto, salendo di 10 pixel; passando al pulsante accanto il pannello cambia larghezza, altezza e posto in mezzo secondo, la sua freccetta scivola sotto il nuovo pulsante, la lista vecchia esce verso il lato che lascia e quella nuova entra dal lato da cui arriva, sempre tagliate dentro il pannello. Products ha tre voci con le icone su quadretti colorati, Solutions due colonne di link, Developers una scheda scura e una lista. Quando il puntatore se ne va il pannello aspetta un quinto di secondo e si chiude, e un ponte invisibile fra la barra e il pannello permette di scendere nella lista senza chiuderlo. Sul telefono e con la tastiera un pulsante apre e chiude la sua lista, la freccia giù porta alla prima voce, Esc chiude e ridà il focus al pulsante, e un tocco fuori chiude.

Come funziona

Un pannello per tutti

Il pannello è un elemento solo dietro alle liste. GSAP gli porta x, width e height a quelli della lista da mostrare, misurata ogni volta con offsetWidth e offsetHeight, in MORPH secondi con expo.out. La lista va sotto il suo pulsante, tenuta dentro la finestra, e la freccetta sotto il pulsante ma ad almeno 26 pixel dagli angoli del pannello.

Le liste che scorrono

La direzione viene dal confronto fra il menu nuovo e quello vecchio: la lista vecchia va di SLIDE pixel verso il lato opposto e sparisce in 0,18 secondi, quella nuova arriva da SLIDE pixel dall’altra parte in 0,45 secondi con power3.out.

Tagliate sul pannello

A ogni aggiornamento ogni lista visibile riceve un clip-path inset calcolato da dove sono lei e il pannello in quel momento: mentre il pannello cambia forma, nulla spunta fuori dai suoi bordi.

Le liste nella pagina

Ogni lista sta nel codice subito dopo il suo pulsante: così il tasto Tab passa dal pulsante alla sua lista e poi al pulsante dopo. Le liste nascoste hanno visibility: hidden e restano fuori dal giro.

Mouse, dito e tastiera

Il puntatore apre passando sopra un pulsante, e col mouse il clic apre soltanto; un dito, la tastiera o uno script aprono e chiudono. Uscito il puntatore, la chiusura aspetta GRACE secondi; il ponte è un ::after della barra alto quanto lo spazio fra barra e pannello (GAP).

Valori da cambiare

NomeFileDi partenzaCosa cambia
MORPHscript.js0.5I secondi del pannello che cambia misura e posto.
SLIDEscript.js36Di quanti pixel scorrono le liste passando da un menu all’altro.
LIFTscript.js10Da quanti pixel più in alto sale il pannello quando si apre.
GRACEscript.js0.2I secondi che il pannello aspetta, uscito il puntatore, prima di chiudersi.
GAPscript.js12I pixel fra la barra e il pannello.

Provali nel Playground

Quando usarla

Per la navigazione di un sito con menu ricchi (prodotti, soluzioni, documentazione) dove ogni menu ha contenuti diversi. Per un menu solo basta una tendina semplice.

Sul telefono

I pulsanti si stringono per stare in uno schermo da 390 pixel; il tocco apre e chiude, il pannello resta dentro lo schermo, e le colonne di Solutions e la scheda di Developers vanno una sotto l’altra.

Con il movimento ridotto

Il pannello non viaggia e le liste non scorrono: il cambio di menu è una dissolvenza veloce, e così l’apertura e la chiusura.

Trappole

  • Le liste vanno tagliate sul pannello mentre cambia forma: senza, quella che esce resta visibile fuori dai bordi per un attimo.
  • Fra la barra e il pannello c’è uno spazio: senza un ponte (un ::after della barra) il puntatore ci passa sopra, la barra lo perde e il pannello si chiude prima che ci si arrivi.
  • Col mouse il clic sul pulsante non deve chiudere: il puntatore l’ha appena aperto passandoci sopra, e un clic che chiude sembrerebbe un errore.
  • Il contenitore della barra non deve allungarsi: in una griglia gli elementi si stirano in altezza (align-items: stretch), e il pannello, appeso al fondo della barra, finirebbe centinaia di pixel più in basso.

Librerie

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

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

Collaudo

Provata il 2 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