
Il menu che si apre dal pulsante
Menu, Transizioni, Testo
Gratis
Le domande frequenti di una piccola stamperia, nello stile minimal: una risposta chiusa non sparisce, ma diventa le sue righe schiacciate in altezza e posate tutte sulla stessa quota, un filetto scuro di due pixel fatto di testo sotto la domanda. Aprendola, l’interlinea cresce dal vivo: le righe si staccano una dopo l’altra, la più lontana per prima, e mentre si separano si gonfiano fino alla loro altezza, si allargano sugli assi del carattere e si posano con un pixel di troppo, finché si leggono.
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 leading accordion</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/full.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the questions of a small print studio. A shut answer is all its lines set on top of one another, with no
leading: one dark rule made of text under the question. Opening it, the leading grows and the lines come
apart one after another until they can be read. The script cuts each answer into its lines; the paragraph
stays for screen readers -->
<div class="faq" data-faq data-autoclic>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q1" aria-expanded="false" aria-controls="faq-a1"><span class="faq__text">What is the smallest run you print?</span><span class="faq__icon" aria-hidden="true"><span class="faq__bar"></span><span class="faq__bar"></span></span></button></h3>
<div class="faq__a" id="faq-a1" role="region" aria-labelledby="faq-q1"><p class="faq__src">Fifty copies. Below that the plates cost more than the paper, so we print you a single proof first and run the rest once you are happy with it.</p></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q2" aria-expanded="false" aria-controls="faq-a2"><span class="faq__text">Which papers can I choose?</span><span class="faq__icon" aria-hidden="true"><span class="faq__bar"></span><span class="faq__bar"></span></span></button></h3>
<div class="faq__a" id="faq-a2" role="region" aria-labelledby="faq-q2"><p class="faq__src">Twelve uncoated stocks, from a thin 90 gsm text paper to a 350 gsm card, all from one mill. We post a free sample pack anywhere in Europe.</p></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q3" aria-expanded="false" aria-controls="faq-a3"><span class="faq__text">Can you match a brand colour?</span><span class="faq__icon" aria-hidden="true"><span class="faq__bar"></span><span class="faq__bar"></span></span></button></h3>
<div class="faq__a" id="faq-a3" role="region" aria-labelledby="faq-q3"><p class="faq__src">Every ink is mixed by hand, so yes. Send us a Pantone reference or a printed swatch and we match it within a shade before the run starts.</p></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q4" aria-expanded="false" aria-controls="faq-a4"><span class="faq__text">How long does an order take?</span><span class="faq__icon" aria-hidden="true"><span class="faq__bar"></span><span class="faq__bar"></span></span></button></h3>
<div class="faq__a" id="faq-a4" role="region" aria-labelledby="faq-q4"><p class="faq__src">Five to seven working days from the proof you approve. When the press is free a rush job can be ready in three; just ask before you order.</p></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q5" aria-expanded="false" aria-controls="faq-a5"><span class="faq__text">Do you ship abroad?</span><span class="faq__icon" aria-hidden="true"><span class="faq__bar"></span><span class="faq__bar"></span></span></button></h3>
<div class="faq__a" id="faq-a5" role="region" aria-labelledby="faq-q5"><p class="faq__src">Yes, flat between two boards so the corners stay sharp. Europe takes two to four days and the rest of the world about a week, always tracked.</p></div>
</div>
</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>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.
28 valori da cambiare
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 fisarmonica a interlinea» da Animorio e adattala al mio sitoOgni risposta è un paragrafo vero. Lo script lo compone una volta in un contenitore nascosto largo quanto la colonna, una parola per span, e legge offsetTop di ogni parola: dove cambia, comincia una riga nuova. Ogni riga diventa un div in posizione assoluta, senza andare a capo, mosso solo da un transform. Il paragrafo resta per gli screen reader, nascosto alla vista, e ha l’attributo hidden finché la risposta è chiusa. Se la colonna cambia larghezza, le righe si tagliano di nuovo.
Da chiusa ogni riga sta a y zero, sulla stessa quota delle altre, schiacciata con scaleY a SQUASH (0,11) e con il transform-origin sulla sua linea di base, misurata con uno span vuoto allineato alla base: tutte insieme fanno un filetto di due pixel. Le righe chiuse hanno l’asse wdth a SHUT_WIDTH, l’asse GRAD a SHUT_GRADE (ingrassa il tratto senza allungare le parole), l’asse opsz a SHUT_OPTICAL (in Roboto Flex la larghezza si stringe molto solo ai corpi grandi) e word-spacing a −0,18 em, così il filetto ha meno interruzioni; l’inchiostro è SHUT_INK.
Aprendo, ogni riga va da zero al suo posto, i volte l’interlinea (LEADING per il corpo), più OVERSHOOT pixel, con power3.out in OPEN secondi, poi torna al posto con sine.inOut. Parte prima la riga più lontana e le altre STAGGER secondi dopo, così nessuna riga ne attraversa un’altra. Chiudendo succede il contrario, con la più vicina per prima e power3.in, e ogni riga atterra un pixel oltre il filetto e torna.
GSAP muove solo la quota di ogni riga. A ogni fotogramma una funzione dà a ogni riga l’altezza dello spazio fra lei e le vicine, diviso l’interlinea (fra SQUASH e 1,05): così due righe non si coprono mai, nemmeno a metà, e le righe si gonfiano mentre l’interlinea cresce, un capello oltre quando corrono un pixel più in là. Dalla stessa altezza vengono larghezza, grado, corpo ottico, spazi e inchiostro; l’altezza del contenitore sta sotto la riga più bassa. La lista ha un’altezza fissa, tutte chiuse più la risposta più lunga, così la sua cima non si muove mai.
Il più sono due filetti di 1,5 pixel: aprendo, l’orizzontale gira di 180 gradi e il verticale di 90 con back.out, e si posano uno sull’altro in un meno vermiglio; chiudendo continuano a girare nello stesso verso. Sotto il puntatore, o al primo tocco del dito, il filetto si apre in filetti più sottili, PEEK pixel l’uno dall’altro, con un elastic.out: le righe si allontanano ma restano schiacciate. Ogni domanda è un pulsante in un titolo con aria-expanded e aria-controls; le frecce, Home e End passano da una domanda all’altra.
| Nome | File | Di partenza | Cosa cambia |
|---|---|---|---|
FIRST | script.js | 0 | La domanda aperta all’apertura della pagina, da 0; −1 per nessuna. |
ONLY_ONE | script.js | true | Aprendo una domanda si chiude quella aperta. |
LEADING | script.js | 1.6 | L’interlinea di una risposta aperta, in volte il corpo del carattere. |
OPEN | script.js | 0.72 | I secondi che una riga ci mette ad arrivare al suo posto (per chiudersi un po’ meno). |
STAGGER | script.js | 0.07 | I secondi fra una riga che parte e la successiva. |
OVERSHOOT | script.js | 1 | I pixel di cui una riga supera il suo posto prima di tornarci. |
SQUASH | script.js | 0.11 | Quanto è schiacciata una riga chiusa, in volte la sua altezza: tutte insieme fanno il filetto. |
SHUT_INK | script.js | 1 | Quanto è scura ogni riga schiacciata: una sopra l’altra fanno un filetto uniforme. |
SHUT_WIDTH | script.js | 45 | L’asse della larghezza delle righe chiuse, più strette di quelle aperte (da 25 a 100). |
SHUT_OPTICAL | script.js | 32 | Il corpo ottico delle righe chiuse: Roboto Flex si stringe molto solo ai corpi grandi. |
SHUT_GRADE | script.js | 150 | L’asse del grado delle righe chiuse: tratti più grassi, stessa larghezza (da 0 a 150). |
PEEK | script.js | 4 | I pixel di cui le righe schiacciate si separano sotto il puntatore, una dopo l’altra. |
Per le domande frequenti di una stamperia, di una casa editrice, di una rivista, di uno studio o di un negozio: ovunque le risposte sono tante e se ne legge una alla volta, e si vuole che anche chiuse si vedano come testo. Funziona meglio con risposte di due-cinque righe; con una riga sola il filetto è una riga normale un po’ più stretta.
La lista si stringe allo schermo con 16 pixel di margine per lato; le domande scendono a 18 pixel e le risposte a 15, così vanno su tre o quattro righe. Il primo tocco del dito apre il filetto come il puntatore, e il tocco apre e chiude. Le domande chiuse sono alte 80 pixel.
Niente righe che si muovono: la risposta passa dal filetto al testo aperto (e ritorno) già al suo posto, in una breve dissolvenza; il più diventa subito un meno vermiglio e la prima risposta è già aperta. Sotto il puntatore il filetto non si apre.
GSAP 3.15.0, Roboto Flex (font variabile, con gli assi della larghezza, del grado e del corpo ottico) 5.3.0.
Compressi con gzip, i tre file della demo pesano 8,6 KB; le librerie: GSAP 28 KB.
Provata il 16 ottobre 2026
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.
Con l’email e la password del tuo account.
oppure con l’email
Hai fatto l’accesso come .
Con l’account scarichi lo zip di ogni animazione e di ogni pacchetto, gratis.