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,fromefromTo; - 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.5comincia 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.
| Ease | Come si sente | Quando |
|---|---|---|
"none" | Velocità costante, meccanica | Barre di avanzamento, rotazioni continue |
"power2.out" | Parte veloce e si posa | Entrate, quasi sempre questa |
"power3.out" | Come sopra, più deciso | Titoli, elementi grossi |
"power2.in" | Parte piano e accelera | Uscite, cose che se ne vanno |
"back.out(1.7)" | Supera e torna indietro | Pulsanti, pastiglie, cose piccole |
"elastic.out(1, 0.5)" | Rimbalza | Con 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
- 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.
- Carica GSAP da CDN con la versione fissata.
- Scrivi la timeline con quattro elementi in fila, usando solo
from, idefaultse le posizioni relative. - 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é. - Aggiungi lo sfalsamento a un gruppo di elementi ripetuti, e prova
staggera 0,03, 0,08 e 0,2 per sentire la differenza. - Chiudi tutto dentro
gsap.matchMediae 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
- Per far entrare un titolo conviene usare:
a)gsap.tob)gsap.fromc)@keyframesd)gsap.set - Il motivo principale è:
a) si scrive meno b) la pagina resta giusta se il codice non parte c) è più veloce d) supporta lo stagger - 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 - Un elemento che entra vuole un ease:
a)inb)outc)noned) indifferente - 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 gsap.matchMediaconprefers-reduced-motionserve 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
- (3 punti) Scrivi la timeline della tua hero, con almeno tre elementi, i
defaultse due posizioni relative. Spiega in una riga perché hai scelto quell'ordine. - (3 punti) Perché una pagina che usa
fromregge meglio di una che usatoquando lo script non arriva? Fai un esempio con un elemento della tua hero.
Mostra risposte corrette
Sezione A
- b:
from, che porta l'elemento dove sta già scritto. - b: senza il codice la pagina è già nel suo stato finale.
- b: sovrappone di tre decimi con quello prima.
- b: un
out, che si posa dove l'occhio legge. - b: niente errore e niente effetto, che è il caso peggiore da cercare.
- 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
fromcontrotoe 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:
outper chi entra,inper 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.