In CSS, what is the difference between overflow: auto and overflow: scroll, and which overflow values turn an element into a scroll container?
answer
- one is conditional, one is not
- scrollbars are not the same as scrollability
- clipping still creates a container
- classic scrollbars eat content width
- reserve the gutter to stop the jump
basics
~20 soverflow: scroll always provides a scrolling mechanism whether or not content overflows; overflow: auto provides one only when it does. Both make the element a scroll container, and so does overflow: hidden, which clips and stays scrollable programmatically but shows no scrollbars.
solid answer
~50 s`overflow` (shorthand for `overflow-x` and `overflow-y`) decides what happens to content that does not fit the box. The default `visible` neither clips nor scrolls — the content just spills out and paints outside the border box. `scroll`, `auto`, `hidden` and `clip` all clip. The difference between `scroll` and `auto` is only about the scrolling affordance: `scroll` always offers one, so on platforms with classic space-consuming scrollbars you get permanently visible tracks even for a box with two words in it, while `auto` shows them only when there is something to scroll. The important subtlety is that `scroll`, `auto` **and** `hidden` all make the element a *scroll container*: `hidden` is not "content deleted", it is "scrollable, but not by the user", so the browser can still scroll it when focus moves into the clipped area. Only `clip` clips without creating a scroll container.
code
css · 9 lines.panel {
block-size: 12rem;
overflow-y: auto;
scrollbar-gutter: stable;
}
.badge-clipper {
overflow: hidden; /* still scrollable programmatically */
}go deeper
Be able to name the five values and say plainly that auto shows scrollbars only when needed while scroll always offers them, and that both clip content the way hidden does.
Explain the scroll-container concept: auto, scroll and hidden all create one, so the browser can scroll a hidden box when focus lands inside it, and descendants can no longer paint outside it.
Show judgment about layout stability: classic versus overlay scrollbars, why scroll is a poor fix for the scrollbar jump, and when scrollbar-gutter: stable is the right reservation on a real product surface.
Own the convention: where scroll containers are allowed to exist in a layout, whether the page has one scroll root or many nested ones, and the cost of nested scrollers for keyboard and assistive-technology users.
## What `overflow` decides Every box has a content area sized by the layout algorithm. When the content inside it is bigger than that area — a long word, a tall list, an image wider than its parent — the box *overflows*. `overflow` is the property that says what the browser does about it. It is a shorthand for the two physical longhands `overflow-x` and `overflow-y`; `overflow: hidden auto` sets them separately. The values: - **`visible`** (initial value): no clipping, no scrolling. The overflowing content is painted outside the box, on top of whatever is next to it. Layout of surrounding boxes is unaffected — they do not move out of the way. - **`hidden`**: the box clips at its padding edge, and the element becomes a scroll container with no user-visible scrolling affordance. - **`clip`**: the box clips and *no* scroll container is created. Nothing — not the user, not the browser — can scroll it. - **`scroll`**: the box clips and always provides a scrolling mechanism. - **`auto`**: the box clips and provides a scrolling mechanism only when the content actually overflows. ## What "scroll container" means A scroll container is a box whose visible area (the *scrollport*) is a window onto a larger scrollable area. The distinction matters because it is not about scrollbars being drawn: ```css .panel { height: 200px; overflow: hidden; /* clipped AND scrollable — just not by the user */ } ``` Because `.panel` is a scroll container, the browser is allowed to scroll it. If a link 400px down inside it receives keyboard focus, or a fragment target lands there, the browser scrolls the hidden content into view and the "hidden" content suddenly appears while the top of the panel disappears. That is the classic surprise behind `overflow: hidden` used as "just clip this". `overflow: clip` exists precisely to express clipping without scrollability. Being a scroll container also changes what descendants can escape the box: a dropdown, tooltip or decoration positioned so it pokes outside the panel is clipped instead of overlapping the neighbours. ## `auto` versus `scroll` in practice `auto` is what you want almost always: scrollbars are an affordance, and an affordance for nothing is noise. `scroll` is chosen deliberately when you want the scrollbar's *space* to be reserved unconditionally, so the layout does not jump the moment content grows past the box height. That reasoning is weaker than it looks, because scrollbars come in two flavours. **Classic** scrollbars take real layout space out of the content area: the scrollport gets narrower, percentage widths inside resolve against a smaller box, and text re-wraps. **Overlay** scrollbars (the macOS default, and touch platforms) are painted over the content, take no space, and fade out when idle — so on those platforms `scroll` looks essentially like `auto`, and the layout-shift problem you were solving does not exist there. The modern answer to the jump is not `overflow: scroll` but `scrollbar-gutter`: ```css .feed { overflow-y: auto; scrollbar-gutter: stable; /* reserve the classic-scrollbar space up front */ } ``` `scrollbar-gutter: stable` reserves the gutter even while nothing is scrollable, so appearing scrollbars no longer shift content; `stable both-edges` reserves it symmetrically on both sides so centred content stays centred. It only affects classic scrollbars — with overlay scrollbars there is no gutter to reserve. Related knobs are `scrollbar-width` (`auto | thin | none`) and `scrollbar-color`; note that `scrollbar-width: none` only hides the scrollbar, the element is still a scroll container and still scrolls. ## The root element special case Overflow on the root element is special: its used value is propagated to the viewport, which is why `html { overflow: hidden }` locks the page rather than clipping a box. If the root's own overflow is `visible`, the value from `body` is propagated to the viewport instead (and `body` then computes to `visible`). This is why `body { overflow: hidden }` is the usual scroll-lock trick, and why setting `height: 100%; overflow: auto` on both `html` and `body` produces confusing double scrollbars. ## Rules of thumb - Reach for `auto` by default; `scroll` only when a permanently reserved affordance is genuinely wanted. - Reach for `clip` when you mean "clip and never scroll". - Remember that any of `auto`, `scroll`, `hidden` turns the box into a scroll container, with all the consequences: descendants can no longer escape it, and the browser may scroll it on your behalf.
- Why does a page sometimes shift sideways the moment content grows long enough to need a vertical scrollbar, and how do you prevent it?A classic, space-consuming scrollbar is taken out of the scrollport, so the content area narrows and everything re-lays-out — a visible horizontal jump. Set `scrollbar-gutter: stable` on the scroll container (or the root) to reserve that space before it is needed, or `stable both-edges` to keep centred content centred. Overlay scrollbars, like the macOS default, never cause the shift because they take no layout space.
- What is different about setting overflow on the root element or on body compared with any other element?Overflow on the root element is propagated to the viewport rather than applying to a box in the page. If the root's overflow is `visible`, the `body` value is propagated instead and `body` itself computes to `visible`. That is why `body { overflow: hidden }` locks page scrolling, and why setting `overflow: auto` plus `height: 100%` on both `html` and `body` tends to produce two competing scrollbars.
- If overflow: hidden still scrolls, how do you express "clip this and never scroll it"?Use `overflow: clip`. It clips at the overflow clip edge and creates no scroll container at all, so neither the user nor the browser can scroll the box — focus moving into clipped content cannot shift it. `overflow-clip-margin` can push the clip edge outward by a length if you need a little bleed for a shadow or focus ring.
saying these in an interview costs you the question
- Thinks overflow: hidden removes the content entirely
- Says auto and scroll are interchangeable in every case
- Assumes scrollbars never take layout space
- Believes only overflow: scroll creates a scroll container
- Thinks overflow: visible clips once a height is set