scroll-marker-group / ::scroll-marker / ::scroll-button()
Carousels
A carousel used to be a scroll container, prev/next buttons, a row of dots, and JavaScript keeping all three in sync. CSS Overflow generates the buttons and the dots from the scroller itself, so the syncing is now the browser’s problem.
Needs Chrome/Edge 135+ or Safari 19+ for the buttons and dots below (Firefox has them behind a flag); other browsers still get a working, snapping scroll list, just without them. Mouse click-and-drag panning isn’t supported anywhere either, no browser does that natively for a scroll container.
Swipe on touch, scroll on a trackpad or wheel, or use the buttons and dots below, all generated by the browser from three CSS declarations.
- Aurora
- Nebula
- Solstice
- Eclipse
- Tidepool
- Meridian
The CSS
.carousel {
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-marker-group: after;
}
.slide {
scroll-snap-align: center;
}
.slide::scroll-marker {
content: '';
}
.carousel::scroll-button(*) {
content: '';
}How it works
The old part is scroll-snap-type: x mandatory with scroll-snap-align on each slide, which settles the scroller on one slide at a time. The new part is scroll-marker-group: after: the browser collects a ::scroll-marker from every slide into one group rendered after the scroller, the dots below. Style ::scroll-marker:target-current and it keeps the right dot lit.
::scroll-button(*) generates the prev and next buttons on the scroll container, wired up and disabled at each end. No click handlers, and no markup for the buttons or the dots.
turns, wins and reset, all CSS
trigonometry, in CSS
switch guests on