Content does not always fit the box you give it. A long word, a wide table or a fixed-height panel can all overflow. CSS lets you decide what happens: show it, clip it, or make the box scroll. It also lets you shape how scrolling feels.
What overflow looks like
.box {
width: 12rem;
height: 6rem;
border: 1px solid #d9e2ec;
}
If the text inside needs more than 6rem, it spills out of the bottom border and over whatever comes next. That is the default, overflow: visible. CSS chooses to show overflowing content rather than hide it, so that nothing is ever lost silently.
The best fix is often to remove the fixed size (use min-height). When a box genuinely must stay a certain size, use overflow.
The overflow values
| Value | Overflowing content | Scrollable? |
|---|---|---|
visible (default) | Shown outside the box | No |
hidden | Clipped | Not by the user, but by script or focus |
clip | Clipped | No, never |
scroll | Clipped | Yes, scrollbars always shown |
auto | Clipped | Yes, scrollbars only when needed |
Use overflow-x and overflow-y to control each direction separately:
.code-sample {
overflow-x: auto; /* horizontal scrollbar only if the line is too long */
}
.chat-log {
max-height: 20rem;
overflow-y: auto;
}
auto is almost always better than scroll, which shows empty scrollbars on some systems even when nothing overflows.
hidden versus clip
Both clip content. The difference is subtle but important:
overflow: hiddenmakes the element a scroll container. It can still be scrolled with JavaScript or when focus moves into hidden content, and it breaksposition: stickyfor descendants.overflow: clipsimply clips. It does not create a scroll container, so sticky descendants keep working.
Use overflow: clip when you only want to trim decorative overflow, for example an image poking out of rounded corners. Reach for hidden when you need its side effect of creating a new formatting context, which also contains floats and margins.
Making scroll areas accessible
A scrollable region must be usable by keyboard. Some browsers make scroll containers focusable automatically, but not all. If a region scrolls and contains no focusable elements, make it focusable and give it a name:
<div class="table-wrapper" tabindex="0" role="region" aria-label="Opening hours by branch">
<table>...</table>
</div>
.table-wrapper {
overflow-x: auto;
}
.table-wrapper:focus-visible {
outline: 3px solid #f0b429;
}
Keyboard users can now tab to the table and scroll it with the arrow keys. Responsive patterns for wide tables and embeds are covered in the Responsive Web Design course.
Truncating text
One line with an ellipsis
.file-name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
All three declarations are needed: white-space: nowrap keeps the text on one line, overflow: hidden clips it, and text-overflow: ellipsis adds the "…". The element also needs a constrained width. Inside a flex item, remember min-width: 0, or the item will grow instead of truncating.
Several lines
.summary {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
This clamps the text to three lines with an ellipsis. The prefixed syntax looks odd, but it is the form that works across all current browsers. An unprefixed line-clamp property is specified but not yet broadly supported.
Truncated text is still in the HTML, so screen readers read it all, but sighted users cannot. Never truncate information people need, such as prices or error messages. Provide a way to see the full text, like a link to the full article.
Breaking long words
Long URLs and unbroken strings can overflow narrow columns. Allow them to break:
.comment {
overflow-wrap: anywhere;
}
Scroll snap
Scroll snapping makes a scroll container settle on specific positions after the user scrolls, like a carousel or a gallery. It needs two parts: the container and its children.
<ul class="carousel">
<li class="slide">...</li>
<li class="slide">...</li>
<li class="slide">...</li>
</ul>
.carousel {
display: flex;
gap: 1rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline: 1rem;
padding: 0 1rem 1rem;
margin: 0;
list-style: none;
}
.slide {
flex: 0 0 80%;
scroll-snap-align: start;
}
scroll-snap-type: x mandatorysnaps horizontally and always settles on a snap point.proximitysnaps only when the user stops close to one.scroll-snap-alignon each child sets which edge snaps:start,centerorend.scroll-paddingon the container offsets the snap position, here keeping 1rem of space at the start.
Setting each slide to 80% of the width lets the next one peek in, which tells users there is more to scroll. This is pure CSS: touch, trackpad, mouse wheel and keyboard scrolling all work.
mandatory can trap content: if a slide is taller or wider than the scroll container, parts of it may become unreachable. Use proximity when slide sizes vary, and test with large text sizes.
Smooth scrolling
scroll-behavior: smooth animates jumps to in-page anchors and scripted scrolling:
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
Wrap it in a reduced-motion query. A long animated scroll down a page is exactly the kind of motion some people need to avoid.
Stopping content hiding under sticky headers
When a link jumps to a section, a sticky header can cover the heading. scroll-margin-top on the target, or scroll-padding-top on the scroll container, adds an offset:
html {
scroll-padding-top: 5rem; /* the height of the sticky header, plus a little */
}
Controlling scroll chaining
When you scroll to the end of a scrollable panel, the browser starts scrolling the page behind it. This is scroll chaining. In modals, side panels and chat windows it is usually unwanted:
.modal-body {
overflow-y: auto;
overscroll-behavior: contain;
}
contain stops the scroll from passing to the parent and also prevents the bounce or pull-to-refresh effect on mobile. none does the same.
Avoiding layout jumps from scrollbars
On systems with classic scrollbars, content shifts sideways when a scrollbar appears. scrollbar-gutter reserves the space in advance:
.panel {
overflow-y: auto;
scrollbar-gutter: stable;
}
It is a newer property; check its Baseline status. Where unsupported, it is ignored and you get the old behaviour.
Finding the cause of horizontal scrolling
An unexpected horizontal scrollbar on the whole page is one of the most common layout bugs.
- Scroll the page sideways and note which part sticks out past the right edge. Inspect it in DevTools.
- Temporarily add
* { outline: 1px solid red; }in the Styles pane to see every box. - Look for fixed widths,
100vw, negative margins, long unbroken strings and flex items withoutmin-width: 0.
Avoid "fixing" it with body { overflow-x: hidden; }. That hides the symptom, can break position: sticky, and leaves content cut off. Find the element that is too wide and fix it.
Summary
overflowdecides whether extra content is shown, clipped or scrollable; preferautooverscroll.hiddencreates a scroll container;clipdoes not, so sticky elements keep working.- Make scrollable regions keyboard-focusable and named when they contain no focusable elements.
- Truncate one line with
text-overflow: ellipsis, several lines with the prefixed-webkit-line-clamp. - Build carousels with
scroll-snap-typeandscroll-snap-align; wrap smooth scrolling in a reduced-motion query.