Obiettivi della lezione
Con ScrollTrigger la barra di scorrimento smette di far scorrere e comincia a comandare: sei tu, col dito, a decidere a che punto è l'animazione. È il pezzo che fa dire «questo sito è 3D» a gente che sta guardando dei rettangoli piatti, e nella Lezione 6 sarà anche quello che muove la scena vera.
Quando hai finito sai fare queste cose:
- Far partire un'animazione quando un elemento arriva a un certo punto dello schermo;
- Leggere e scrivere
starteendsenza andare a tentoni, con i marcatori; - Legare l'avanzamento al dito con
scrub; - Bloccare una sezione con
pine raccontare qualcosa mentre resta ferma; - Spegnere il blocco sul telefono, dove quasi sempre fa danni.
L'idea in una riga
Un'animazione normale ha un orologio: parte e dura un secondo. Un'animazione con ScrollTrigger ha la posizione della pagina al posto dell'orologio. Tu dici dove comincia e dove finisce, e in mezzo comanda il dito.
Da qui discendono i due usi, che sono diversi e si confondono sempre.
- Far scattare qualcosa quando un elemento entra in scena. L'animazione poi va per conto suo, col suo tempo. È l'entrata delle sezioni, e copre la maggior parte dei casi.
- Legare l'avanzamento al dito (
scrub). L'animazione non ha un tempo suo: sta esattamente dove sei arrivato tu. Se torni su, torna indietro. È questa che dà la sensazione di controllare una scena.
Il primo ScrollTrigger
gsap.registerPlugin(ScrollTrigger);
gsap.from(".sezione-due .card", {
y: 40,
opacity: 0,
duration: 0.6,
stagger: 0.1,
ease: "power3.out",
scrollTrigger: {
trigger: ".sezione-due", // l'elemento da sorvegliare
start: "top 80%", // quando il SUO top tocca l'80% dell'altezza schermo
toggleActions: "play none none reverse"
}
});
start: "top 80%" si legge così: la prima parola è un punto dell'elemento, la seconda un punto dello schermo. Quando il bordo alto della sezione arriva all'altezza dell'80 per cento dello schermo, cioè poco sopra il fondo, scatta. Stessa grammatica per end.
toggleActions sono quattro parole per quattro momenti, sempre in quest'ordine: quando entri, quando esci dal fondo, quando rientri tornando su, quando esci dall'alto. "play none none reverse" vuol dire: entra e parte, esce e non fa niente, torna indietro e si riavvolge. Le altre parole possibili sono pause, resume, restart, complete, none.
I marcatori, che si accendono e non si spengono mai abbastanza presto
Aggiungi markers: true dentro a scrollTrigger e vedi in pagina due righe verdi e due rosse: dove comincia e dove finisce, sull'elemento e sullo schermo. Con quelle capisci start in trenta secondi invece che a tentoni. Toglile prima di pubblicare, perché si vedono anche in produzione.
scrub: l'animazione al guinzaglio
gsap.to(".barra", {
scaleX: 1,
ease: "none", // con scrub l'ease va quasi sempre tolto
scrollTrigger: {
trigger: ".capitolo",
start: "top top",
end: "bottom bottom",
scrub: 0.5 // mezzo secondo di ritardo morbido dietro al dito
}
});
Due cose su cui si sbaglia sempre.
scrub: true contro scrub: 0.5. Con true l'animazione è incollata al dito, al pixel: preciso e un po' nervoso. Con un numero, insegue con quel ritardo e il movimento diventa morbido. Mezzo secondo è un buon punto di partenza, e sopra il secondo comincia a sembrare che il sito risponda in ritardo.
L'ease va tolto. Con scrub la curva del tempo ce l'ha già il dito: mettere anche un power3.out vuol dire due curve sovrapposte, e il risultato è un movimento che accelera dove non dovrebbe. Su scrub si scrive ease: "none" e si guarda meglio.
pin: la sezione che si ferma e racconta
È l'effetto più riconoscibile del genere: arrivi a una sezione, la pagina smette di scorrere, la sezione resta ferma e dentro succede qualcosa, poi la pagina riparte. Sono tre righe.
const racconto = gsap.timeline({
scrollTrigger: {
trigger: ".racconto",
start: "top top",
end: "+=2000", // quanto scorrimento serve per attraversarla: 2000 pixel
scrub: 0.5,
pin: true
}
});
racconto
.from(".passo-1", { opacity: 0, y: 30 })
.to(".passo-1", { opacity: 0, y: -30 })
.from(".passo-2", { opacity: 0, y: 30 })
.to(".passo-2", { opacity: 0, y: -30 })
.from(".passo-3", { opacity: 0, y: 30 });
Il numero da capire è end: "+=2000": sono i pixel di scorrimento che servono per attraversare tutto il racconto. Più è alto, più piano si svolge. Conta un migliaio di pixel per passaggio e poi aggiusta guardando: sotto i 600 per passaggio la gente non fa in tempo a leggere, sopra i 2000 sembra che il sito si sia bloccato.
Il pin è la cosa che rompe di più
Per bloccare una sezione ScrollTrigger la avvolge in un contenitore e le dà un'altezza: da quel momento i tuoi position: sticky, i height: 100% e le trasformazioni sul genitore possono comportarsi in modo strano. Se qualcosa salta, la prima cosa da provare è togliere pin e vedere se il problema resta.
Tre guai che capitano a tutti
Le misure prese troppo presto. ScrollTrigger calcola le posizioni quando parte. Se dopo arrivano dei caratteri, delle immagini senza width e height, o del contenuto caricato dopo, le posizioni sono sbagliate e l'animazione scatta nel punto sbagliato. Si sistema con ScrollTrigger.refresh() dopo che il contenuto è arrivato, e si previene mettendo le dimensioni alle immagini.
Il blocco sul telefono. Una sezione bloccata su uno schermo alto e stretto, con la barra del browser che compare e sparisce, è la ricetta per un'esperienza brutta. Quasi sempre sul telefono il racconto si serve meglio in verticale, uno sotto l'altro.
const mm = gsap.matchMedia();
mm.add("(min-width: 900px) and (prefers-reduced-motion: no-preference)", () => {
// qui dentro il racconto bloccato: solo su schermi larghi e per chi vuole il movimento
gsap.timeline({ scrollTrigger: { trigger: ".racconto", pin: true, scrub: 0.5, end: "+=2000" } })
.from(".passo-1", { opacity: 0, y: 30 });
});
Quando la condizione smette di valere, GSAP smonta quello che c'è dentro da solo: ridimensionando la finestra il blocco si toglie senza lasciare in giro contenitori appesi.
Troppi ScrollTrigger. Venti animazioni legate allo scorrimento su una pagina sola reggono benissimo finché nessuno tocca niente, e vanno ricalcolate tutte a ogni cambio di misura della finestra. Se la pagina singhiozza durante il ridimensionamento, il conto da guardare è quello.
Laboratorio: la sezione che si blocca
Obiettivo: una sezione del tuo progetto che si ferma e racconta tre cose, con il ripiego verticale sul telefono.
Consegna
- Scrivi la sezione in HTML con i tre passaggi uno sotto l'altro, leggibili senza JavaScript. È anche la versione per il telefono: la scrivi una volta sola.
- Accendi i marcatori e fai un primo ScrollTrigger senza animazioni, solo per vedere dove cadono
startedend. - Aggiungi il blocco con
pin: trueescrub: 0.5, e regolaendfinché i tre passaggi si leggono senza fretta. - Prova tre valori di
scrub(true,0.3,1.5) e scegli, scrivendo perché. - Chiudi tutto in
matchMediasopra i 900px, e guarda la pagina a 390px: i tre passaggi devono stare in colonna, senza blocco. - Spegni i marcatori e rileggi la pagina dall'alto come farebbe una persona qualsiasi.
Risultato atteso
Una sezione che si blocca e racconta su schermo largo, e la stessa sezione che su telefono è un elenco verticale che si legge. Se per farla funzionare sul telefono hai dovuto scrivere un secondo HTML, torna al punto 1: il contenuto è uno, il movimento è un di più.
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
- In
start: "top 80%", l'80% si riferisce:
a) all'elemento b) all'altezza dello schermo c) alla pagina d) alla durata - Con
scrub, l'avanzamento è deciso:
a) dal tempo b) dalla posizione dello scorrimento c) dall'ease d) dal browser - Su un'animazione con
scrub, l'ease:
a) va messo forte b) va tolto,ease: "none"c) è obbligatorio d) va messoin end: "+=2000"vuol dire:
a) dura 2000 millisecondi b) servono 2000 pixel di scorrimento per attraversarla c) finisce a 2000px dal fondo d) 2000 fotogrammi- Se un'animazione scatta nel punto sbagliato dopo che sono arrivate le immagini:
a) si alzascrubb) serveScrollTrigger.refresh(), e le misure sulle immagini c) si toglie il pin d) si cambia ease - Il
pinsul telefono:
a) va sempre acceso b) quasi sempre conviene spegnerlo e impilare c) è obbligatorio d) non funziona mai
Sezione B: risposta aperta
- (3 punti) Spiega la differenza fra far scattare un'animazione e legarla al dito con
scrub, con un esempio per ognuna preso dal tuo progetto. - (3 punti) Scrivi il
matchMediadella tua sezione bloccata e di' che cosa vede chi arriva da un telefono.
Mostra risposte corrette
Sezione A
- b: la prima parola è un punto dell'elemento, la seconda dello schermo.
- b: dalla posizione dello scorrimento, che prende il posto dell'orologio.
- b: la curva ce l'ha già il dito, due curve si sommano male.
- b: sono pixel di scorrimento.
- b: le posizioni vanno ricalcolate, e le immagini vogliono le dimensioni.
- b: su schermi alti e stretti, con la barra del browser che va e viene, conviene impilare.
Sezione B, risposte modello
7. Far scattare: le tre card dei servizi entrano quando la sezione arriva all'80% dello schermo, poi l'animazione va per conto suo in mezzo secondo. Con scrub: il prodotto ruota di 90 gradi mentre attraverso la sezione, e se torno su torna indietro, perché l'avanzamento è la mia posizione.
8. Esempio: mm.add("(min-width: 900px) and (prefers-reduced-motion: no-preference)", ...) con dentro il blocco. Da telefono i tre passaggi restano in colonna e si leggono scorrendo normalmente, che è poi come sono scritti nell'HTML.
Valutazione (su 12)
- 11-12: ottimo. 8-10: sufficiente. < 8: rivedi
start/ende la differenza fra scatto escrub.
Riassunto della lezione
Cosa hai imparato
- ScrollTrigger mette la posizione della pagina al posto dell'orologio.
- Due usi diversi: far scattare qualcosa, oppure legare l'avanzamento al dito con
scrub. start: "top 80%"si legge punto dell'elemento, punto dello schermo; imarkerslo fanno capire in trenta secondi.- Con
scrubl'ease si toglie, perché la curva la fa già il dito. pinè il pezzo che rompe di più, e sul telefono quasi sempre si spegne.
Prossimi passi
Nella Lezione 4, La prima scena WebGL apriamo il canvas: scena, camera, luce, un oggetto e il giro di disegno. Alla fine hai qualcosa che gira davvero in pagina, ed è la base su cui la Lezione 6 attacca lo scorrimento.
Vuoi farlo con il tuo team?
Questo percorso lo porto dentro le aziende, sui prodotti che avete già: restano vostre le scene e il modo di misurarle.