← Single-axis scroll containers
v153 · css overflow · grammar + computed values
overflow: scroll clip — combination semantics
How the two-keyword overflow grammar and its per-axis computed-value rules turn “scrollable on one axis, clip on the other” into a single-axis scroll container — and what that does to scroll offsets, scrollbars, and programmatic scrolling on the clipped axis.
syntax
Verbatim from CSS Overflow 3 §3.1:
overflow
Value: <'overflow-block'>{1,2}
Initial: visible
Applies to: block containers, flex containers, and grid containers
“The overflow property is a shorthand property that sets the specified values of overflow-x and overflow-y in that order. If the second value is omitted, it is copied from the first.” So overflow: scroll clip means overflow-x: scroll; overflow-y: clip — the first keyword is always the x (inline-in-horizontal-writing) axis, never the “primary” one. The longhands take the same value set: visible | hidden | clip | scroll | auto (plus overlay as a legacy alias of auto).
The value definitions that matter here, verbatim:
clip— “the box’s content is clipped to its overflow clip edge and that no scrolling user interface should be provided by the UA to view the content outside the clipping region. In addition, unlikeoverflow: hiddenwhich still allows programmatic scrolling,overflow: clipforbids scrolling entirely, through any mechanism. Unlikehidden, this value does not cause the element to establish a new formatting context.”scroll— “the content is clipped to the overflow clip edge, but can be scrolled into view. Furthermore, if the user agent uses a scrolling mechanism that is visible on the screen (such as a scroll bar or a panner), that mechanism should be displayed whether or not any of its content is clipped.”auto— “Likescrollwhen the box has scrollable overflow; likehiddenotherwise.”
computed-value rules (what each axis becomes)
The classification that drives everything else — verbatim from the same section:
“The
scroll,auto, andhiddenvalues are known as the scrollable values ofoverflow. They cause the box to be a scroll container and the affected axis to be a scrollable axis. […] Thevisibleandclipvalues are known as the non-scrollable values. However, if the other axis specifies a scrollable value, a specified value ofvisiblecomputes toauto, enabling scrolling in its axis. If neither axis computes to a scrollable value, the box is not a scroll container. If only one axis computes to a scrollable value (i.e. the other axis isclip), the box is a single-axis scroll container.”
| Declared (x / y) | Computed result | Scroll container type |
|---|---|---|
scroll / clip | unchanged | single-axis (x) |
auto / clip | unchanged | single-axis (x) — no scrollbar until there is x-overflow |
clip / scroll | unchanged | single-axis (y) |
scroll / hidden | unchanged | dual-axis — y is still scrollable programmatically |
scroll / visible | visible → auto | dual-axis |
clip / visible | unchanged (no scrollable value) | not a scroll container |
The spec’s parenthetical — “i.e. the other axis is clip” — is the whole point: clip is the only non-scrollable value that does not compute away when paired with a scrollable value. hidden cannot produce a single-axis container because it is itself scrollable.
the disabled axis: offsets, scrollbars, programmatic scrolling
| Behavior | Contract |
|---|---|
| Scroll offset on the clipped axis | Always 0 — scrollTop/scrollLeft read 0 and programmatic scrolls (scrollTo(), scrollBy(), offset assignment) on that axis do not change it |
| Scroll metrics | scrollWidth/scrollHeight still measure the full overflowing content — clipping does not shrink the measurement |
| User scrolling | None on the clipped axis: no scrollbar, no wheel/touch/keyboard scrolling — “forbids scrolling entirely, through any mechanism” |
scrollIntoView() | Scrolls only the scrollable axis of a single-axis container |
Dynamic change to clip | Switching an axis from a scrollable value to clip clamps that axis back to offset 0 and repaints |
| Formatting context | clip alone does not establish one (unlike hidden); a box that is a scroll container (the other axis) still establishes an independent formatting context |
error and edge behavior
- Unknown keywords — anything outside the value set (
visible | hidden | clip | scroll | auto | overlay) makes the declaration invalid at parse time and it is dropped (standard CSS error handling); there is no partial application. - Three or more keywords — the grammar is
{1,2}; a third keyword invalidates the whole declaration. - Replaced elements — CSS Overflow 3’s properties apply to block/flex/grid containers; Level 4 expands
overflowto replaced elements, which is out of scope for this feature’s sources. - Scroll snap — snap-point interaction with single-axis containers is a separate, not-yet-enabled feature in Chromium (
SingleAxisScrollContainersForScrollSnap) and an open spec question (csswg-drafts #14018); treat snap behavior on the scrollable axis as unsettled.
examples
/* x-scrollable, y-disabled: a single-axis (x) scroll container */
.rail {
overflow: scroll clip; /* = overflow-x: scroll; overflow-y: clip */
}
/* equivalent longhands, scrollbar only when x-overflow exists */
.rail-lazy {
overflow-x: auto;
overflow-y: clip;
}
/* NOT equivalent — hidden keeps y programmatically scrollable,
so this stays a dual-axis scroll container */
.rail-broken {
overflow-x: auto;
overflow-y: hidden;
}
// The disabled axis holds no offset:
const rail = document.querySelector('.rail');
rail.scrollTo({ top: 100, left: 40 });
console.log(rail.scrollTop); // 0 — the y axis is clipped, not scrollable
console.log(rail.scrollLeft); // 40 — the x axis scrolls
Source: semantics per CSS Overflow 3 §3.1 and WPT programmatic-API assertions
compatibility
Same interim status as the overview table (flag still experimental at trunk — see the overview ship-status note). BCD’s multiple_keywords key (Chrome 68 / Firefox 61 / Safari 13.1) records only the two-keyword syntax, not single-axis behavior.
| Browser | overflow: scroll clip → single-axis scroll container |
|---|---|
| Chrome | Enabled by default 153 (per the listing); flag experimental at trunk |
| Edge | Not separately reported |
| Firefox | Unknown — Mozilla #1418 open, no signal |
| Safari | Unknown — WebKit #680 open, no signal |
security and privacy
No new exposure: a grammar/computed-value change with no I/O. The one authoring hazard is that clip disables scrolling through any mechanism on that axis — including assistive-technology and keyboard scrolling — so content must never depend on being reachable by scrolling the clipped axis.