Prompt and context
You need a horizontal product-card carousel and want the browser to generate previous/next scroll buttons and position markers. Explain CSS Overflow Module Level 5, unsupported-browser fallback, accessibility, and release criteria.
CSS Overflow 5 defines ::scroll-button() and ::scroll-marker controls generated by a scroll container, plus scroll-marker-group for grouping them. Browser support is still evolving, so the interview tests capability boundaries and progressive enhancement rather than treating the feature as a universal baseline.
What the interviewer evaluates
The interviewer wants you to distinguish the scroll container, scroll buttons, and marker group; explain axis selection, disabled states, and scrolling behavior; preserve native links and keyboard paths; provide a usable fallback; and validate with real devices and assistive technology instead of only checking pixels.
Clarifying questions
Content and layout
Ask whether this is a paged card carousel, continuous gallery, or tab list; how many items appear per page; whether item widths are fixed; and whether free scrolling is allowed.
Browser scope
Confirm target browsers, supported-version window, JavaScript policy, and whether the product can hide experimental enhancement in browsers without support.
Interaction and accessibility
Confirm keyboard focus order, screen-reader announcement of the current item, touch and wheel behavior, reduced-motion preference, and feedback when a button is unavailable.
30-second answer
“I would build a normal horizontal scroll container with focusable cards as the baseline, then enable scroll-marker-group and ::scroll-button() where CSS Overflow 5 is supported. Buttons trigger scrolling, but cards keep their own semantics and keyboard path. I would gate enhancement with @supports selector(::scroll-button(*)). Unsupported browsers retain native scrolling or a small JavaScript control, and keyboard, screen-reader, touch, and reduced-motion tests are release gates.”
Step-by-step solution
Step 1: Establish a usable baseline
Start with ordinary layout, overflow-x: auto, an explicit scroll-snap policy, and visible focus styling. Every card has a heading, link, or button, so content remains reachable without generated markers.
Step 2: Enable native controls
In supporting browsers, set a marker group and use ::scroll-button(left) and ::scroll-button(right) for previous and next controls. The specification associates these buttons with the originating scroll container; availability follows remaining scrollable content, so they are not ordinary decorative pseudo-elements.
.carousel {
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-marker-group: after;
}
.carousel::scroll-button(left),
.carousel::scroll-button(right) {
inline-size: 2.5rem;
block-size: 2.5rem;
}Step 3: Detect capability
Gate enhancement styles with @supports or selector capability detection. When detection fails, do not hide the scrollbar, cards, or a hand-built fallback. When it succeeds, preserve stable dimensions so generated controls do not change the visible content range unexpectedly.
Step 4: Preserve semantics and keyboard paths
Generated pseudo-element buttons should not be the only operation path. Define consistent focus movement, Home/End, arrow-key, and touch behavior; scroll a card into view when focus reaches it. A screen reader should announce the carousel name, current card, and action, not merely “next.”
Step 5: Handle axis and RTL
Button arguments relate to the scroll axis, so physical left and right are not automatically logical start and end. Test RTL, vertical writing modes, and other writing modes separately. Prefer logical dimensions and spacing, then verify visual and keyboard directions.
Step 6: Design the fallback
Without support, keep native horizontal scrolling. If explicit buttons are required, a small JavaScript layer can observe scroll position and update disabled, current-item, and aria state. Both paths should share card data and semantics rather than maintaining two content trees.
Step 7: Set release gates
Test supporting and non-supporting browsers, keyboard, touch, wheel, 200% zoom, high contrast, screen readers, and prefers-reduced-motion. Track visible cards on first paint, accidental activations, lost focus, scroll latency, and fallback coverage; a screenshot cannot prove that controls are usable.
Model answer
I would treat ordinary horizontal scrolling and card semantics as the baseline, then layer CSS Overflow 5 controls on top. Capability detection enables scroll-marker-group and ::scroll-button() where available; elsewhere scrolling still works, with a small JavaScript fallback only if explicit controls are a requirement. Generated buttons never replace links, focus, or screen-reader semantics. I would test RTL, vertical writing, unavailable states, visible focus, touch, and reduced motion, then use a browser matrix and real assistive technology to confirm every card remains reachable.
Common mistakes
- Mistake: Treating
::scroll-button()as a normal button available everywhere. → Why it fails: CSS Overflow 5 support is still evolving. → Fix: Detect capability and retain native scrolling. - Mistake: Hiding the scrollbar and card links, leaving only dots. → Why it fails: Keyboard and assistive technology users can lose the content path. → Fix: Make card semantics work independently; markers are additional navigation.
- Mistake: Mapping physical left/right directly to RTL logic. → Why it fails: Visual direction, writing mode, and logical direction can differ. → Fix: Test buttons, focus, and scroll results separately in RTL and vertical writing.
- Mistake: Testing clicks only. → Why it fails: Focus loss, zoom overflow, and reduced-motion issues remain invisible. → Fix: Make keyboard, touch, screen-reader, and 200% zoom checks release criteria.
Follow-ups and responses
What is the boundary between ::scroll-button() and a normal button?
It is generated by the scroll container and tied to scrolling context, which determines its style and availability. Product-specific actions, analytics, or confirmation flows may still need a real button or JavaScript.
Why keep native scrolling?
It is the usable path when enhancement is unavailable and covers touch, wheel, and user preferences. If enhancement fails, users can still reach the content.
How do you avoid layout shifts from generated controls?
Reserve control space, use stable container dimensions and logical spacing, and compare first-paint card count and snap positions across capability branches.
When should you avoid this feature?
Use ordinary scrolling with a mature control when target browsers lack support, carousel state is complex, or the team cannot maintain a reliable fallback. Reducing JavaScript is not worth reducing access.