Exhibit 04 of 17
A carousel on rails
Swipe, scroll or use the dots. The carousel is a scroll box with scroll-snap, so it always stops square on a slide.
The exhibit
How it works
The track is a row of full-width slides with overflow-x: auto. scroll-snap-type: x mandatory on the track and scroll-snap-align: start on each slide make every scroll end exactly on a slide. The numbered dots are ordinary links to each slide’s id; following one scrolls it into view.
Where the browser supports them, ::scroll-marker and ::scroll-button() let CSS generate the dots and the arrows itself, with the current dot marked by :target-current, and the link dots step aside.
The key CSS
Cut from this exhibit’s stylesheet as it is served.
/* the track is a row of full-width slides that scrolls sideways and stops on each one */
.x-carousel .track {
display: grid; grid-auto-flow: column; grid-auto-columns: 100%; gap: 16px;
overflow-x: auto; overscroll-behavior-x: contain;
scroll-snap-type: x mandatory; scroll-behavior: smooth;
}
.x-carousel .slide { scroll-snap-align: start; scroll-snap-stop: always; }
/* newer browsers: CSS makes the dots and the arrows itself, so the link dots step aside */
@supports selector(::scroll-marker) {
.x-carousel .track { scroll-marker-group: after; }
.x-carousel .track::scroll-marker-group { display: flex; justify-content: center; gap: 10px; padding-top: 14px; }
.x-carousel .slide::scroll-marker { content: ""; width: 14px; height: 14px; border: 1.5px solid var(--ink); border-radius: 50%; }
.x-carousel .slide::scroll-marker:target-current { background: var(--ink); }
.x-carousel .track::scroll-button(left) { content: "←" / "Previous"; }
.x-carousel .track::scroll-button(right) { content: "→" / "Next"; }
.x-carousel .dots { display: none; }
}
Accessibility
The track takes keyboard focus (tabindex="0", which is HTML) so the arrow keys scroll it, and it is labelled as a region. The link dots move the page’s scroll position and fragment, so the page may jump to show the carousel, and the URL changes. Nothing auto-advances. A script carousel could announce “slide 2 of 4” as it moves; here each slide is labelled, but nothing is announced when it changes.
Browser support
scroll-snapWorks in this browser.Not in this browser: Universal. Checked 2026-10-14: Chromium 149 yes, Firefox 141 yes.::scroll-markerWorks in this browser.Not in this browser: The numbered links under the slides do the same job. Checked 2026-10-14: Chromium 149 yes, Firefox 141 no.
