Sviluppo web
Caroselli con scroll-snap: tre proprietà e nessun JavaScript
scroll-snap trasforma un contenitore con overflow in un carosello che si aggancia, senza JavaScript. Le tre proprietà, i limiti e la verifica da tastiera.
In sintesi
- Tre proprietà bastano: scroll-snap-type sul contenitore, scroll-snap-align sul figlio, scroll-padding per il primo elemento.
- mandatory per schede di larghezza uguale, proximity quando le schede hanno misure diverse.
- Il CSS non dà l'etichetta né il contatore: quelli restano da scrivere, e servono.
Risposta breve: scroll-snap-type più scroll-snap-align trasformano un contenitore con overflow-x: auto in un carosello che si aggancia, senza JavaScript. Il trascinamento resta nativo e la tastiera continua a funzionare.
Le tre proprietà che servono
| Proprietà | Dove | Cosa fa |
|---|---|---|
scroll-snap-type: x mandatory | contenitore | aggancia sull'asse orizzontale, senza vie di mezzo |
scroll-snap-align: start | figlio | dice dove l'elemento si ferma |
scroll-padding-inline | contenitore | tiene conto del padding, così il primo elemento non resta tagliato |
Il codice
.carousel {
display: flex;
gap: 1rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline: 1rem;
overscroll-behavior-inline: contain;
scrollbar-width: none;
}
.carousel > * {
flex: 0 0 min(80vw, 22rem);
scroll-snap-align: start;
}
@media (prefers-reduced-motion: reduce) {
.carousel { scroll-behavior: auto; }
}
overscroll-behavior-inline impedisce che il gesto prosegua sulla pagina quando il carosello arriva in fondo: senza, su un telefono lo scorrimento verticale si blocca. min(80vw, 22rem) dà una scheda quasi piena su telefono e fissa su desktop.
mandatory o proximity
mandatory obbliga lo scatto e va bene per schede della stessa larghezza. Quando le schede hanno misure diverse lo scatto sembra un salto: in quel caso proximity è più gentile, perché aggancia solo se sei già vicino al punto.
Il supporto è ampio dal 2019. Su Safari datato serve ancora -webkit-overflow-scrolling: touch per lo scorrimento inerziale, e la proprietà va scritta prima di overflow.
Il limite
Il carosello con scroll-snap non ha frecce, né contatore, né etichetta. Chi usa uno screen reader non sa quante schede ci sono: serve un'etichetta accessibile sul contenitore e un indicatore testuale del tipo «3 di 8». Il CSS da solo non li dà, e senza di loro il carosello è un elenco orizzontale invisibile.
Come verificarlo
- Trascina con trackpad, touch e tastiera: lo scatto deve cadere sullo stesso elemento.
- Controlla l'ordine di tabulazione: deve seguire l'ordine visivo, non quello del DOM se li hai separati.
- Attiva
prefers-reduced-motionnel sistema: nessuno scorrimento animato. - Riduci la finestra a 320 px: la prima scheda non deve restare tagliata dal padding.
Dove continuare
Nel catalogo: blocco testimonial, componenti e blocchi. Le guide: centrare un elemento e navbar su mobile; il confronto: Tailwind contro CSS Modules.
Domande frequenti
Serve ancora una libreria di caroselli?
Per lo scorrimento no. Una libreria serve se vuoi autoplay, loop infinito o frecce con stato: cose che scroll-snap non fa.
Perché lo scatto non funziona?
Quasi sempre perché il contenitore non ha un overflow dichiarato, o perché la proprietà è su un antenato. scroll-snap-type va sull'elemento che scorre.
Come nascondo la scrollbar?
Con <code>scrollbar-width: none</code> e <code>::-webkit-scrollbar</code> per i motori più vecchi. Ricorda che nascondere la barra toglie anche l'indizio che si può scorrere.
Funziona in verticale?
Sì, con <code>scroll-snap-type: y</code>. Su una pagina intera è però invasivo: la userei solo dentro un pannello con altezza fissa.
Il carosello fa male al CLS?
No, se le schede hanno un rapporto dichiarato. Il rischio è la larghezza, non l'altezza: una scheda senza misura cambia il numero di elementi visibili mentre carica.