Puoi ricostruire un’animazione while-scrolling da premio in Webflow senza una riga di codice — una gallery in cui ogni immagine scala verso l’alto mentre entra nella viewport e torna piccola mentre esce. Il difficile non è l’animazione in sé. È il layout. Azzecca la struttura e le interazioni diventano quasi banali; sbagliala e nessun ritocco la renderà fluida su ogni schermo.
Guardando da vicino l’originale, tre cose la rendono sfuggente. Il transform origin cambia a seconda che un’immagine stia scalando in entrata dal basso o in uscita dall’alto. Ogni immagine inizia a scalare nel momento in cui entra in vista e si ferma quando è del tutto visibile, a prescindere da dimensione dello schermo o aspect ratio. E lo scaling fa sembrare che ogni immagine resti brevemente attaccata al bordo della viewport. Nessuna di queste ha una soluzione nativa ovvia — finché non cambi prospettiva.
È proprio quel cambio di prospettiva la vera lezione. Un po’ di pensiero laterale, il posizionamento assoluto, un’espressione calc() e le interazioni while-scrolling native di Webflow bastano a spingere la piattaforma sorprendentemente lontano.
Come funziona
Due immagini battono una impossibile. Il transform origin deve essere diverso tra entrata e uscita, e un singolo elemento non può avere due origin. Così ogni cella della griglia riceve due copie dell’immagine, avvolte in un div che diventa la cella vera e propria. Una copia (cc1) porta l’origin per lo scaling verso l’alto dal basso; l’altra (cc2) porta l’origin per lo scaling verso il basso dall’alto. Ne resta visibile una sola per volta — le alterni con una semplice interazione scroll-into-view. Il problema difficile si scioglie in due problemi facili.
Il rettangolo grigio — il modello mentale chiave. Una timeline while-scrolling misura il suo 0%–100% sull’altezza della viewport, ma l’altezza di un’immagine è guidata dalla larghezza della viewport, quindi non esiste una percentuale che resti corretta su tutti i dispositivi. La soluzione è smettere di animare rispetto all’immagine e animare rispetto allo spazio vuoto. Immagina l’immagine appoggiata in fondo alla viewport e un rettangolo grigio che riempie lo spazio sopra: quel rettangolo è del tutto visibile esattamente quando l’immagine deve iniziare a scalare, e inizia a uscire esattamente quando l’immagine è cresciuta del tutto. La sua altezza, per definizione, è la viewport meno l’immagine — calc(100vh - 100%) dentro un wrapper alto quanto l’immagine. È indipendente dal dispositivo, e dà finalmente allo 0% e al 100% un significato concreto.
Sono i trigger, non le immagini, a guidare la timeline. Quel rettangolo lo costruisci come un div in posizione assoluta (il “trigger”) dentro un wrapper immagine position: relative. Un trigger sta sopra l’immagine per lo scale-up, uno speculare sta sotto per lo scale-down. L’interazione while-scrolling si applica al trigger con gli offset impostati su “inizia quando è del tutto in vista, finisci quando inizia a uscire”. L’animazione punta all’immagine sorella del trigger, così una sola interazione, applicata per classe, guida ogni cella della griglia insieme.
Celle vuote come div block. La griglia della gallery è irregolare — la maggior parte delle celle è vuota. Invece di piazzare a mano ogni immagine con il posizionamento della griglia (un incubo su larga scala), riempi le celle occupate con immagini e quelle vuote con div block vuoti, in ordine di lettura. Riempire la griglia diventa una passeggiata.
Il CMS ha bisogno di custom element + custom attribute. Una collection list non può dare a ogni item la sua combo class o la sua posizione nella griglia dal Designer. Il workaround unisce due delle funzioni più potenti di Webflow: avvolgi ogni immagine in un custom element e collega il suo attributo class a un campo di testo del CMS (così ogni item può portare classi di transform origin diverse), e dai a ogni item un custom tag attribute pari al suo slug così che un code embed possa targettizzare gli item uno a uno e impostarne i margini dai campi numerici del CMS.
Come si usa
-
Sezione segnaposto. Aggiungi una sezione (senza stili) con un container e un content wrapper impostato su
display: flex, centrato,height: 100vh. Serve solo a nascondere la gallery sotto la piega. -
Griglia della gallery. Aggiungi una seconda sezione con un container e un content wrapper impostato su
display: grid, quattro colonne,gap: 25vw. Riempi le celle occupate con un’img(width100%) e ogni cella vuota con un div block vuoto, replicando il layout dell’originale riga per riga. -
Raddoppia ogni immagine. Avvolgi ogni immagine in un div (diventa la cella), poi duplica l’immagine al suo interno. Dai alla prima copia la combo class
cc1e alla secondacc2(impostacc2sudisplay: none). Poi aggiungi le combo class di transform origin per copia — es.cc-top-left/cc-top-rightper le copie in scale-up ecc-bottom-left/cc-bottom-rightper quelle in scale-down — leggendo gli angoli giusti dall’originale per ogni cella. -
Costruisci i trigger. Imposta il wrapper immagine su
position: relative. Al suo interno aggiungi un div (position: absolute,width: 100%) e dagli un’altezza di:height: calc(100vh - 100%);Dagli una combo class
cc-abovee un offset bottom di100%così sta sopra l’immagine. Duplicalo comecc-belowcon un offset top di100%così sta sotto. -
Animazione di scale-up. Seleziona il trigger above e aggiungi un’interazione while-scrolling (play scroll interaction), impostata per iniziare quando l’elemento è del tutto in vista e finire quando inizia a uscire. Aggiungi una action scale sull’immagine sorella:
0al keyframe 0%,1al 100%. Punta alla classe semplicegallery-section-image(senza combo) così scalano entrambe le immagini della cella, e imposta il trigger per applicarsi per classe — poi copia il trigger in ogni cella. -
Animazione di scale-down. Sul trigger below, aggiungi la stessa interazione while-scrolling ma inverti lo scale:
1allo 0%,0al 100%. Applica per classe e copia in ogni cella. -
Scambia l’immagine visibile. Aggiungi un’interazione scroll-into-view sul trigger above con un gruppo di action hide/show: mostra
cc1(impostato sublock), nascondicc2(impostato sunone). Aggiungi un’animazione scroll-out-of-view vuota così l’interazione si resetta e si ripete a ogni passaggio. Fai lo speculare sul trigger below (mostracc2, nascondicc1). -
Pulizia. Resetta opacità e sfondo di test dei trigger, e imposta
pointer-events: nonesulla classe base del trigger così non blocca mai i clic.
Renderla guidata dal CMS
-
Flex, non grid. Per una collezione, imposta la lista sulla stessa classe content-wrapper più una combo
cc-flex:display: flex, wrap, allineato in alto a sinistra. Dai a ogni collection item la classe image-wrapper piùcc-flexe questa width:/* 4 item per riga, 3 gap da 25vw tra loro */ width: calc((100% - 75vw) / 4); -
Collega le classi via custom element. Avvolgi ciascuna delle due immagini in un custom element e collega il suo attributo
classa un campo di testo del CMS che contiene i nomi esatti delle classi base + combo (separati da spazio). Applica la transform scale a questi wrapper invece che direttamente alle immagini. -
Posiziona ogni item dal CMS. Aggiungi i campi numerici
margin-rightemargin-leftalla collezione e dai a ogni item un custom tag attribute pari al suo slug. In un code embed, targettizza quell’attributo e imposta i margini orizzontali dai campi, dove ogni cella vuota vale il 25% di una riga:/* margin-left / margin-right sono campi numerici CMS (numero di celle vuote) */ margin: 0 calc(var(--margin-right) * 25%) 0 calc(var(--margin-left) * 25%); -
Responsività. In portrait, porta la griglia a due colonne e imposta le celle vuote su
display: none; per la versione CMS, sovrascrivi i margini a0, imposta la width dell’item sucalc((100% - 25vw) / 2), allunga i wrapper sull’asse Y e aggiungi una classeimg-cover(object-fit: cover) così gli aspect ratio misti riempiono comunque in modo pulito.