Carousels and Slide Decks Without JavaScript
Scroll Snap
`scroll-snap-type` makes a container snap to its children as the user scrolls.
What you'll learn
- Build a snapping horizontal carousel
- Pick `mandatory` vs `proximity`
- Style the snap targets
scroll-snap makes a scrolling container snap to its children
when the user scrolls. Useful for carousels, slide decks, and
full-page sections.
A Horizontal Carousel
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
gap: 1rem;
}
.carousel > .slide {
flex: 0 0 90%; /* each slide is 90% of the container width */
scroll-snap-align: start;
} <div class="carousel">
<div class="slide">1</div>
<div class="slide">2</div>
<div class="slide">3</div>
</div> Scroll. Releases snap to the next slide.
mandatory vs proximity
mandatory— ALWAYS snaps to a child. Even mid-scroll.proximity— snaps only if the user lands close enough to a target. More natural for free-scrolling.
Pick mandatory for slides; proximity for casual content
browsing.
Snap Alignment
.slide {
scroll-snap-align: start; /* snap to slide's start */
scroll-snap-align: center; /* center the slide in the view */
scroll-snap-align: end; /* snap to slide's end */
} Vertical Full-Page Sections
html {
scroll-snap-type: y mandatory;
}
section {
height: 100dvh;
scroll-snap-align: start;
} Every <section> becomes a “page” that snaps as you scroll.
Padding & Margin Inside the Container
scroll-padding shrinks the snap viewport — useful for sticky
headers:
html {
scroll-padding-top: 80px; /* leave room for the sticky header */
} Browser Support
All modern browsers. Safe to use.
End of Chapter
That’s modern CSS. Last chapter: accessibility, performance, and the rest of what makes a site production-ready.
Semantic HTML →