The different overflow values define whether an element has scrollbars, whether it is user and programmatically scrollable, and whether it is a scroll container (which creates a new block formatting context) when that element's contents overflow and, in the case of scroll, even when they don't.
The visible value
The default value is visible. By default, if content overflows a container's constraints, the contents are not contained to the container. An element that defaults or is explicitly set to visible doesn't have scrollbars, is not user or programmatically scrollable, and is not a scroll container. This value does not create a new block formatting context.
css
div {
overflow: visible;
}
<div>
<h2>overflow: visible;</h2>
</div>
<div>
<p>
The <code>overflow</code> property in this example is set to
<code>visible</code>. No scroll container is created; the content just
overflows the container.
</p>
</div>
With visible, no clipping occurs, so the overflowing content is visible outside the element's padding box, potentially overlapping adjacent content.
The scroll value
With scroll, content is clipped at the element's padding box and can be scrolled into view. User agents display scroll bars in both directions, whether or not any content is overflowing, which prevents scroll bars from appearing and disappearing as content changes. Printers may still print overflow content.
The element is always a scroll container — even when there is no overflowing content — and is both user-scrollable and programmatically scrollable.
css
div {
overflow: scroll;
}
<div>
<h2>overflow: scroll;</h2>
</div>
<div>
<p>
The <code>overflow</code> property in this example is set to
<code>scroll</code>. A scroll container is created; a scrollbar is always
visible, even if not needed.
</p>
</div>
In the first example, even though the content is not overflowing, a scroll container is still created. In the second example, the content is clipped to the padding box, with a scroll bar enabling scrolling to the overflowing content.
The auto value
With auto, whether the element has scrollbars and is a scroll container depends on whether the element has overflowing content. When the element contains overflowing content, it behaves like scroll: the overflowing content is clipped at the element's padding box, and overflow content can be scrolled into view using scroll bars. Unlike scroll, user agents display scroll bars only if the content is overflowing. If content fits inside the element's padding box, it looks the same as with visible, but still establishes a new formatting context. The element box is a scroll container only when there is overflowing content.
css
div {
overflow: auto;
}
<div>
<h2>overflow: auto;</h2>
</div>
<div>
<p>
The <code>overflow</code> property in this example is set to
<code>auto</code>. Because there is overflowing content, a scroll container
is created. The content is clipped to the padding box and a scroll bar
enables scrolling to the overflowing content.
</p>
</div>
When using the two value syntax, if one value is set to visible, that visible overflow direction will behave as auto if the other value is not visible or clip.
The hidden value
With hidden, overflowing content is clipped at the element's padding box. There are no scroll bars and the clipped content is not visible (i.e., it's "hidden").
If there is overflowing content, the element is a scroll container. While there are no scroll bars and the user cannot view the content outside the clipped region by actions such as dragging on a touch screen or using the scroll wheel on a mouse, the hidden overflow content can be scrolled into view.
If the content contains focusable elements, tabbing brings the currently focused element into view. Content can also be scrolled to programmatically. Setting a value for the scrollLeft or scrollTop property scrolls that distance from the left or top edge, respectively. You can also scroll using the scrollTo() method.
css
div {
overflow: hidden;
}
<div>
<h2>overflow: hidden;</h2>
</div>
<div>
<p>
The <code>overflow</code> property in this example is set to
<code>hidden</code>. While hidden,
<a
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Content_categories#interactive_content"
>interactive content</a
>
can be scrolled into view when focused. Because content overflows, the
element is a scroll container, even though no scroll bars are present.
Tabbing will give this
<input aria-label="input" placeholder="input" /> focus and scroll it into
view. This content is also programmatically scrollable.
</p>
</div>
The first example does not have overflowing content and is not a scroll container. The second example has overflowing content that is clipped to the padding box. Even though there is no scroll bar enabling scrolling to the overflowing content, the content can be scrolled into view, such as by tabbing to the <input> in the hidden content. The second example is a scroll container.
The clip value
With clip, content that overflows is by default hidden, there are no scroll bars, and programmatic scrolling is not possible. The element is not a scroll container and no new formatting context is created. If the clipped content includes interactive content, hidden focusable content still receives keyboard focus, but that content will not scroll into view, making it inaccessible to keyboard users.
With clip, overflow content is clipped at the element's overflow clip edge that is defined using the overflow-clip-margin property. The clipped content overflows the element's padding box by the <length> value of overflow-clip-margin, which defaults to 0px.
css
div {
overflow: clip;
}
<div>
<h2>overflow: clip;</h2>
</div>
<div>
<p>
The <code>overflow</code> property in this example is set to
<code>clip</code>. When hidden,
<a
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Content_categories#interactive_content"
>interactive content</a
>
can NOT be scrolled into view when focused. Overflowing content is clipped
to the container. No scroll container is created. Tabbing will give this
<input aria-label="input" placeholder="input" /> focus but will not scroll
it into view. Keyboard users will not be able to reach this content. This
content is also not programmatically scrollable.
</p>
</div>
<fieldset>
<legend>Select a <code>overflow-clip-margin</code> value</legend>
<ul>
<li>
<label
><input type="radio" name="overflow" value="0" /> overflow-clip-margin:
0;</label
>
</li>
<li>
<label
><input type="radio" name="overflow" value="3em" />
overflow-clip-margin: 3em;</label
>
</li>
</ul>
</fieldset>
The second example's overflowing content is clipped. Tabbing to the <input> in the hidden content gives the element focus, but does not scroll it into view, making that content inaccessible to keyboard users.
When using the two value syntax, if one value is set to clip, that clip overflow direction will behave as hidden if the other value is not set to visible or clip.
ul {
list-style-type: none;
}
label {
font-family: monospace;
}
:has([value="0"]:checked) div {
overflow-clip-margin: 0;
}
:has([value="3em"]:checked) div {
overflow-clip-margin: 3em;
}
@supports not (overflow-clip-margin: 0) {
body::before {
content: "Your browser doesn't support overflow-clip-margin yet.";
background-color: wheat;
display: block;
text-align: center;
padding: 1rem 0;
width: 100%;
}
}
With scroll-driven animations
When creating scroll-driven animations using the scroll() function, consider using clip instead of hidden if there is no interactive content within the clipped area, unless you explicitly want to create a scroll container.
With both hidden and clip, the overflow gets clipped, but overflow: clip doesn't create a scroll container, so clipped elements are skipped when the user agent goes up the DOM tree looking for the nearest ancestor scroll container.
Because overflow: hidden creates a scroll container when there is overflowing content, you might accidentally create a scrolling-ancestor that doesn't scroll. But only use clip if you are certain you won't clip any interactive content.
div {
height: 10em;
width: 15em;
border: 3px solid;
padding: 10px;
background-color: #ededed;
background-clip: content-box;
}
p {
font-size: 1.5rem;
line-height: 1.6;
font-family: sans-serif;
}
h2 {
font-family: monospace;
}
body {
height: 98vh;
overflow: clip;
display: flex;
flex-flow: row wrap;
gap: 3em;
}