overflow, scroll-snap & keyboard access
Swipeable rows with scroll snap
Lesson 17 of 20 · 10 min · Module 5: Pages for every situation
Horizontal rows of cards are everywhere on phones. Scroll snap makes them land neatly on a card after each swipe, with pure CSS. The row must still work for keyboard users and must not make the whole page scroll sideways.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Scroll a row inside its container
- Snap scrolling to items with scroll-snap
- Keep a scrolling region keyboard accessible
The idea
overflow-x: auto lets a row scroll inside itself, and scroll-snap-type: x mandatory makes it stop on snap points. Each slide sets scroll-snap-align: start. Slides with flex: 0 0 80% leave a peek of the next one, which tells people there is more. tabindex="0" and an aria-label let keyboard users focus the row and scroll it with the arrow keys.
.row {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
.row > * { scroll-snap-align: start; }
01Scroll inside, not the page
overflow-x: auto contains the wide row, so only the row scrolls. Without it, the extra width pushes the whole page sideways on phones, which feels broken.
02Snap points
scroll-snap-type on the container turns snapping on; scroll-snap-align on each child says which edge snaps. mandatory always settles on a slide, while proximity only snaps when you stop close to one.
.carousel { scroll-snap-type: x mandatory; scroll-padding-inline: 16px; }
.slide { scroll-snap-align: start; }
03Keyboard and screen readers
A scrolling region with no focusable content cannot be reached with the keyboard. tabindex="0" makes it focusable, and aria-label gives it a name when focus arrives.
Your turn
.carousel scroll sideways with overflow-x: auto and snap with scroll-snap-type: x mandatory. 2) Give every .slide flex: 0 0 80% and scroll-snap-align: start. 3) Add tabindex="0" and aria-label="Featured courses" to the <ul class="carousel">. On a 390px screen the page itself must not scroll sideways.What the checks look for
- The row scrolls sideways
- Scrolling snaps to the slides
- Slides snap at their start
- Each slide takes 80% of the row
- Slides never shrink
- Keyboard users can focus the named row
- The page does not scroll sideways on a phone
Take this with you
Scroll snap gives app-like swiping with plain CSS.
Go a little further
Add scroll-padding-inline: 16px to the row so snapped slides keep a little space from the edge.