Home/ Corsi/ Siti 3D con GSAP e WebGL/ Lezione 2: GSAP

Lezione 2: GSAP: animare in modo prevedibile

Metà dei siti che sembrano 3D non hanno un poligono dentro. Qui impari tween, timeline, ease e sfalsamento, e soprattutto perché si usa «from»: la pagina resta giusta anche quando il codice non parte.

Animare una pagina web con GSAP
Indice dei contenuti
Lezione 2 di 7 · Movimento Teoria + Laboratorio + Mini-test

Obiettivi della lezione

La metà dei siti che sembrano 3D non hanno un poligono dentro: hanno del movimento fatto bene. Si comincia da qui perché è la parte che rende di più, pesa pochi kilobyte e funziona su qualunque cosa abbia uno schermo.

Alla fine di questa lezione sai:

  • Installare GSAP, da CDN o da npm, e sapere che cosa stai caricando;
  • Scrivere un movimento con gsap.to, from e fromTo;
  • Mettere in fila più movimenti con una timeline, e spostarli senza rifare i conti;
  • Scegliere un ease che non sembri un ascensore;
  • Spegnere tutto per chi ha chiesto meno movimento, con gsap.matchMedia.

Le animazioni CSS bastano, finché non bastano

Per far comparire una cosa, i @keyframes del CSS vanno benissimo e non serve caricare niente. Il problema arriva al terzo movimento.

Con il CSS ogni animazione conosce solo sé stessa: per farne partire una dopo l'altra scrivi dei animation-delay a mano, e quando decidi che la prima dura due decimi di più li devi rifare tutti. Con una timeline di GSAP le metti in fila una volta e i ritardi se li calcola lei.

Poi ci sono tre cose che il CSS non fa e che servono sempre: fermare un'animazione a metà e ripartire da dov'è, animare una cosa che non è una proprietà CSS (un numero che conta, la rotazione di un oggetto 3D), e legare l'avanzamento allo scorrimento invece che al tempo. L'ultima è tutta la Lezione 3.

Quanto costa GSAP, in kilobyte e in euro

Il cuore di GSAP compresso sta intorno ai 70 KB, ScrollTrigger ne aggiunge una quarantina. Ed è gratuito, plugin compresi: la loro documentazione scrive che «GSAP and all the plugins are now freely available on npm». Se hai letto in giro che ScrollTrigger si paga, era vero prima e non lo è più.

Metterlo in pagina

Due strade, e cambiano poco. Da CDN, per provare o per un sito statico:

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

Con un progetto che ha un impacchettatore, da npm:

npm install gsap
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

Quella riga con registerPlugin serve solo per i plugin. Dimenticarla è il primo errore di tutti: il codice non dà errore e lo scorrimento non fa niente.

La versione si scrive, sempre

Hai visto gsap@3.15.0 e non gsap@latest. Con latest il giorno che esce una versione nuova se la prende il tuo sito, senza che nessuno l'abbia provata. Su questo sito è successo davvero con un'altra libreria, e da allora ogni indirizzo esterno porta il numero di versione attaccato.

to, from, fromTo

Un movimento in GSAP è una frase sola: questi elementi, verso questi valori, in questo tempo.

// da dove sta adesso, VERSO questi valori
gsap.to(".pallino", { x: 300, rotation: 180, duration: 1 });

// DA questi valori, verso dove sta adesso: e' quello che userai il 90% delle volte
gsap.from(".titolo", { y: 40, opacity: 0, duration: 0.8 });

// da qui a qui, senza guardare dove sta
gsap.fromTo(".barra", { scaleX: 0 }, { scaleX: 1, duration: 0.6 });

from è quello che si usa quasi sempre, e il motivo è pratico: la pagina resta giusta anche se il codice non parte. Scrivi il titolo dove deve stare, e GSAP lo fa arrivare lì partendo da venti pixel più in basso. Con to invece devi scrivere il titolo dove non deve stare, e il giorno che lo script non arriva la pagina resta rotta.

Il primo argomento è un selettore CSS, un elemento o un elenco di elementi. Il secondo è un oggetto con le proprietà da animare più le impostazioni: duration, delay, ease, stagger, repeat.

Lo sfalsamento, che da solo fa metà del lavoro

gsap.from(".card", {
  y: 30,
  opacity: 0,
  duration: 0.5,
  stagger: 0.08,        // 80 millisecondi di scarto fra una card e la successiva
  ease: "power3.out"
});

Otto centesimi di secondo di scarto trasformano sei card che appaiono insieme in sei card che arrivano. È la riga con il miglior rapporto fra fatica e resa di tutto il corso.

La timeline: metterli in fila

Una timeline è un contenitore di movimenti che sa in che ordine vanno. Li aggiungi in fila e partono in fila, senza che tu conti i ritardi.

const t = gsap.timeline({
  defaults: { duration: 0.6, ease: "power3.out" }   // vale per tutti, si scrive una volta
});

t.from(".pastiglia",   { y: 20, opacity: 0 })
 .from(".titolo",      { y: 40, opacity: 0 }, "-=0.3")   // comincia 3 decimi PRIMA che finisca il precedente
 .from(".sottotitolo", { y: 20, opacity: 0 }, "-=0.4")
 .from(".bottone",     { scale: 0.9, opacity: 0 }, "-=0.2");

Il terzo argomento è la posizione, ed è la cosa che rende una timeline diversa da quattro animazioni con dei ritardi. Vale la pena impararne tre forme:

  • "-=0.3" comincia tre decimi prima della fine di quello di prima. È quella che dà il senso di sovrapposizione.
  • "<" comincia insieme al precedente.
  • 0.5 comincia a mezzo secondo dall'inizio della timeline, qualunque cosa sia successa prima.

Il guadagno si vede quando cambi idea: allunghi la durata del titolo e tutto il resto si sposta da sé. Con i delay scritti a mano rifaresti quattro conti.

L'ease, che è dove sta il gusto

L'ease dice come si distribuisce il movimento nel tempo. È la differenza fra una cosa che si muove e una cosa che sembra viva, e cambiare una parola cambia tutto.

EaseCome si senteQuando
"none"Velocità costante, meccanicaBarre di avanzamento, rotazioni continue
"power2.out"Parte veloce e si posaEntrate, quasi sempre questa
"power3.out"Come sopra, più decisoTitoli, elementi grossi
"power2.in"Parte piano e acceleraUscite, cose che se ne vanno
"back.out(1.7)"Supera e torna indietroPulsanti, pastiglie, cose piccole
"elastic.out(1, 0.5)"RimbalzaCon parsimonia, e mai su un testo lungo

La regola corta: le cose che entrano usano un out, perché il movimento si posa dove l'occhio poi legge; le cose che escono usano un in, perché accelerano via. Chi mette "none" ovunque ottiene un sito che sembra un tabellone dell'aeroporto.

Le durate

Fra 0,3 e 0,8 secondi sta quasi tutto. Sotto i 2 decimi il movimento non si legge, sopra il secondo la gente aspetta. Se una cosa deve durare due secondi, quasi sempre vuol dire che dentro ci sono due movimenti e uno va tolto.

Chi ha chiesto meno movimento

Nei sistemi operativi c'è un'impostazione che dice «riduci le animazioni», e chi la accende di solito ha un motivo serio: emicranie, vertigini, disturbi vestibolari. Il browser la passa alle pagine, e ignorarla vuol dire far star male qualcuno.

GSAP ha lo strumento apposta, e sono sei righe:

const mm = gsap.matchMedia();

mm.add("(prefers-reduced-motion: no-preference)", () => {
  // qui dentro tutte le animazioni: girano solo per chi non ha chiesto di ridurle
  gsap.from(".card", { y: 30, opacity: 0, duration: 0.5, stagger: 0.08 });
});

Quello che sta fuori da quel blocco resta com'è. Ed è il motivo per cui prima insistevo su from: se il blocco non gira, la pagina è già nel suo stato finale, leggibile e completa. Con to avresti una pagina con i titoli fuori posto.

Laboratorio: l'entrata della tua hero

Obiettivo: la hero del progetto scelto nella Lezione 1 che entra con una timeline, e che resta leggibile se il codice non parte.

Consegna

  1. Scrivi la hero in HTML e CSS nello stato finale: come deve vedersi a movimento finito. Provala con JavaScript disattivato: deve essere già a posto.
  2. Carica GSAP da CDN con la versione fissata.
  3. Scrivi la timeline con quattro elementi in fila, usando solo from, i defaults e le posizioni relative.
  4. Lavora sull'ease: prova la stessa timeline con "none", "power2.out" e "back.out(1.7)" e guardale una dietro l'altra. Scegli e scrivi perché.
  5. Aggiungi lo sfalsamento a un gruppo di elementi ripetuti, e prova stagger a 0,03, 0,08 e 0,2 per sentire la differenza.
  6. Chiudi tutto dentro gsap.matchMedia e provalo accendendo «riduci animazioni» nelle impostazioni del tuo sistema.

Risultato atteso

Una hero che entra in poco meno di un secondo e mezzo in tutto, e la stessa hero che con le animazioni ridotte compare a posto senza muoversi. La prova che conta è la seconda: se spegnendo il movimento la pagina si rompe, la timeline sta facendo un lavoro che spettava al CSS.

Mini-test di autoverifica

Istruzioni

Sezione A: 6 domande a risposta multipla (1 punto). Sezione B: 2 domande aperte (3 punti). Totale 12. Soglia: 60% (8/12).

Sezione A: risposta multipla

  1. Per far entrare un titolo conviene usare:
    a) gsap.to   b) gsap.from   c) @keyframes   d) gsap.set
  2. Il motivo principale è:
    a) si scrive meno   b) la pagina resta giusta se il codice non parte   c) è più veloce   d) supporta lo stagger
  3. Nella timeline, "-=0.3" vuol dire:
    a) dura 3 decimi in meno   b) comincia 3 decimi prima della fine del precedente   c) ritarda di 3 decimi   d) torna indietro
  4. Un elemento che entra vuole un ease:
    a) in   b) out   c) none   d) indifferente
  5. Se dimentichi gsap.registerPlugin(ScrollTrigger):
    a) esce un errore rosso   b) lo scorrimento non fa niente, in silenzio   c) la pagina non carica   d) GSAP lo registra da solo
  6. gsap.matchMedia con prefers-reduced-motion serve a:
    a) fare il responsive   b) far girare le animazioni solo per chi non ha chiesto di ridurle   c) risparmiare kilobyte   d) caricare il plugin

Sezione B: risposta aperta

  1. (3 punti) Scrivi la timeline della tua hero, con almeno tre elementi, i defaults e due posizioni relative. Spiega in una riga perché hai scelto quell'ordine.
  2. (3 punti) Perché una pagina che usa from regge meglio di una che usa to quando lo script non arriva? Fai un esempio con un elemento della tua hero.
Mostra risposte corrette

Sezione A

  1. b: from, che porta l'elemento dove sta già scritto.
  2. b: senza il codice la pagina è già nel suo stato finale.
  3. b: sovrappone di tre decimi con quello prima.
  4. b: un out, che si posa dove l'occhio legge.
  5. b: niente errore e niente effetto, che è il caso peggiore da cercare.
  6. b: accende il movimento solo per chi non l'ha ridotto.

Sezione B, risposte modello

7. Esempio: const t = gsap.timeline({ defaults: { duration: 0.6, ease: "power3.out" } }); poi pastiglia, titolo a "-=0.3", sottotitolo a "-=0.4". L'ordine segue l'occhio: prima la pastiglia che dice di che si parla, poi il titolo, poi la riga che spiega.

8. Con from il titolo sta già scritto al posto giusto nell'HTML e GSAP lo fa arrivare da più in basso: se lo script non arriva, il titolo è lì. Con to dovrei scrivere nel CSS opacity: 0, e senza lo script resterebbe invisibile: una hero vuota.

Valutazione (su 12)

  • 11-12: ottimo. 8-10: sufficiente. < 8: rivedi from contro to e le posizioni della timeline.

Riassunto della lezione

Cosa hai imparato

  • GSAP è gratuito, plugin compresi, e si carica con la versione fissata.
  • from è quello da usare: la pagina resta giusta anche se il codice non parte.
  • La timeline mette in fila e ricalcola i tempi da sé; le posizioni relative danno la sovrapposizione.
  • L'ease è dove sta il gusto: out per chi entra, in per chi esce, durate fra 0,3 e 0,8.
  • Lo stagger è la riga con la resa più alta del corso.
  • Tutto dentro gsap.matchMedia, perché chi ha chiesto meno movimento ha un motivo.

Prossimi passi

Nella Lezione 3, ScrollTrigger leghiamo questi movimenti allo scorrimento: la sezione che si blocca e racconta, la barra che avanza, il passaggio guidato dal dito invece che dal tempo. È la lezione che fa sembrare 3D un sito che non lo è.

Lo stesso lavoro, sul tuo progetto, in aula

Si parte dal modello che hai già, si monta la scena e si misura: quello che esce si può pubblicare.

Guarda le date
Federico BoggiaRispondo io, in giornata

Ciao! Dimmi che ti serve: un corso online, un workshop di AI in aula a Livorno o la formazione per la tua azienda.

Scrivimi su WhatsApp