Content does not always fit. A long word overflows its column, an image is wider than its container, a fixed-height panel has more text than room for. The overflow property decides what happens then, and the difference between its values is the difference between a usable layout and a broken one.
What are the overflow values?
.panel {
overflow: visible; /* the default: content spills out and is still visible */
}
.panel {
overflow: hidden; /* content is clipped, nothing scrolls */
}
.panel {
overflow: auto; /* scrollbars appear only when needed */
}
.panel {
overflow: scroll; /* scrollbars are always there */
}
The default is visible, which means the content simply overflows and is drawn outside the box. That is the correct behaviour for most elements: a paragraph should be as tall as its text, and nothing should be clipped by accident.
Where it matters is the two-axis form, where horizontal and vertical overflow are set independently.
.code-block {
overflow-x: auto; /* long lines scroll sideways */
overflow-y: hidden; /* and never scroll vertically */
}
Setting only one axis to something other than visible forces the other to auto automatically, which surprises people who write overflow-x: hidden and then find a vertical scrollbar appearing.
When should you use auto and when scroll?
auto shows scrollbars only when there is something to scroll, which is the right default for a content area of unknown size. scroll always reserves the space, which avoids the layout shifting when the content happens to fit or not — at the cost of a permanently visible scrollbar that does nothing.
There is a third option that is often the best of both: overflow-y: auto together with scrollbar-gutter: stable, which reserves the scrollbar space whether or not it is needed.
.sidebar {
overflow-y: auto;
scrollbar-gutter: stable;
max-height: 100vh;
}
One thing to be careful about: a scroll container is not reachable by keyboard unless it can be focused. A scrollable region that the user cannot reach with the tab key is a known accessibility problem, and the fix is to make it focusable and give it a name.
<div class="table-scroll" tabindex="0" role="region" aria-label="Results table">
<table>...</table>
</div>
How do you cut off a single line of text?
A single-line truncation needs three properties working together. The overflow has to be hidden, the element must not wrap, and the text-overflow property must be set to ellipsis.
.card-title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
Without white-space: nowrap the text wraps instead of truncating, and without text-overflow the text is simply cut off mid-word with no indication. All three are needed. The ellipsis needs the overflow to be hidden, and it only works on a single line — for multiple lines, the line clamping properties are the tool.
.excerpt {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
How do you stop one long word breaking the layout?
A long unbroken string — a URL, a hash, a German compound — has no spaces to break at, so it pushes the box wider than its container. There are two ways to handle it, and the choice depends on whether the content must stay on one line.
/* let the word break, even mid-word */
.break-anywhere {
overflow-wrap: anywhere;
}
/* break only when the word cannot fit on a line by itself */
.break-when-needed {
overflow-wrap: break-word;
}
On a grid or flex track, the same problem appears as the track refusing to shrink. Setting min-width: 0 on the flex or grid item lets it shrink below the size of its content, which is the fix for the very common "one long word blew out my row" bug.
.row {
display: flex;
}
.row > * {
min-width: 0; /* items may shrink below their content width */
}
What about images that are too big?
An image that is wider than its column is usually fixed with a maximum width, and the height then follows the aspect ratio automatically.
img {
max-width: 100%;
height: auto;
}
The height: auto is not optional. Without it, an image with both a width and a height attribute keeps that height and gets squashed, because the browser uses the attribute as the box size. The two-line rule above is the standard reset for responsive images.
How do you keep a scroll area under control?
Three properties shape how a scroll container behaves, and each solves a different problem.
overflow-y: auto adds a scrollbar only when the content actually needs one. overflow-y: scroll always reserves the space, which stops the layout jumping when a panel that had a scrollbar suddenly does not. overflow-y: hidden clips the content and offers no way to reach what is below, so it is a last resort for a visual effect rather than a solution for a real overflow.
overscroll-behavior controls what happens when the user reaches the end of a scroll container. The default is that the scroll is chained to the page behind it, which is usually what you want for an ordinary list. Set overscroll-behavior: contain on a modal panel and the page behind it stays put instead of scrolling when the panel is scrolled to its end.
.panel {
max-height: 60vh;
overflow-y: auto;
/* scrolling inside the panel does not scroll the page behind it */
overscroll-behavior: contain;
}
.sidebar {
position: sticky;
top: 1rem;
/* the list scrolls, the page does not move when it reaches the end */
max-height: calc(100vh - 4rem);
overflow-y: auto;
overscroll-behavior: contain;
}The scrollbar-gutter: stable property solves the related problem of content shifting sideways when a scrollbar appears and disappears. It reserves the scrollbar space permanently, so a table that gains a vertical scrollbar does not narrow by a few pixels and reflow every line of text.
For the horizontal case, remember that a value of visible on one axis is not allowed - the specification turns it into auto. So if you set overflow-x: hidden on an element that also needs overflow-y: visible, the vertical value is computed as auto, and the element becomes a scroll container in both directions.
Quick reference
visibleis the default and never clips;hiddenclips without scrolling.autoadds scrollbars only when needed;scrollalways reserves them.- Setting one axis to a non-visible value forces the other to
auto. - Single-line truncation needs
overflow: hidden,white-space: nowrapandtext-overflow: ellipsistogether. - Use
overflow-wrapto break long words, andmin-width: 0to let flex and grid items shrink. - A scroll container needs
tabindex="0"to be reachable by keyboard.
Try it yourself: put a very long URL in a narrow column and watch it push the layout wide. Add overflow-wrap: anywhere and confirm the layout holds. Then make a card title truncate to one line with an ellipsis, and remove each of the three properties in turn to see which one was doing the work.