v157 · css · scroll snap · behaviour probe

Propagation probe

This feature adds no syntax, so CSS.supports() alone cannot see it — it changes which scroller consumes a snap area. The probe below measures the behaviour itself: set a snap container’s scrollTop to a deliberately misaligned offset, let the browser re-snap, and read back where it settled. A control scroller first proves the method works at all in this browser.

Probing this browser…

Step 0 — the prerequisite

Propagation only exists where overflow: auto clip keeps clip as a pure clip. Older engines coerce the pair to hidden, which is a two-axis scroll container that traps snap areas by design.

Computed overflow values for an overflow-x auto, overflow-y clip element
declaredcomputed in this browsermeaning

Step 1 & 2 — control, then test

Both scrollers are scroll-snap-type: y mandatory. In the control, cards with scroll-snap-align: start sit directly inside it. In the test, the same cards sit inside a horizontal overflow: auto clip carousel — their vertical alignment only reaches the outer scroller if per-axis propagation is active.

control — direct snap areas

160px filler — no snap area
card A · scroll-snap-align: start
card B · scroll-snap-align: start
tail filler

test — snap areas inside overflow: auto clip

160px filler — no snap area
tail filler
Not run yet. “Run both probes” sets each outer scroller 37px past its card edge and reports where each one settles.

Inspect: what does the inner carousel consume?

The carousel’s own horizontal snapping is plain, shipped scroll snap — scroll it sideways (it is keyboard-focusable; use arrow keys) and the readout reports each horizontal settle via scrollsnapchange where available, falling back to scrollend + measurement.

No horizontal snap observed yet.

what the probe is testing

// No new syntax: the contract is WHO consumes the snap area.
// Outer: scroll-snap-type: y mandatory
// Inner: overflow-x: auto; overflow-y: clip  (single-axis scroller)
// Cards: scroll-snap-align: start            (both axes, logical)

outer.scrollTop = cardEdge - 37;   // deliberately misaligned
// mandatory snap re-aligns programmatic scrolls, so after settling:
//   old behaviour: scrollTop === cardEdge - 37  (card's y-alignment is
//                  trapped by the carousel, outer has no snap areas)
//   new behaviour: scrollTop === cardEdge       (y-alignment propagated
//                  up to the outer scroller)

The control runs the identical sequence against directly-nested cards. If the control fails to re-snap, the method is unusable in this browser and the test result is reported as inconclusive, not as a verdict on propagation.

see also