CSS overflow:hidden — Clipping, BFC Side Effects, and Fixes
Quick answer
💡overflow:hidden clips content at the element's border box, creates a block formatting context, and breaks position:sticky on any descendant. It also clips box-shadow, outline, and transformed elements that extend beyond the container boundary. If only horizontal clipping is needed, use clip-path:inset(0) instead — it does not trigger BFC or affect overflow-y.
Error symptoms
- ✕
Box-shadow on a child element is cut off at the parent boundary - ✕
position:sticky inside a container stops working after adding overflow:hidden - ✕
Rotated or scaled elements are clipped and partially invisible - ✕
Scrollable content disappears instead of scrolling - ✕
Negative margins or absolutely positioned elements outside the parent are invisible - ✕
Adding overflow:hidden to fix a float layout causes other elements to disappear
Common causes
- •overflow:hidden is used to contain floats but clips child elements that extend beyond the border box
- •overflow:hidden on any ancestor element breaks position:sticky — sticky needs a scrollable ancestor, not a clipping one
- •overflow-x:hidden forces overflow-y to become auto, creating an unexpected scrollbar
- •Box-shadow and outline render outside the border box and are clipped by overflow:hidden
- •CSS transform on a child positions it outside the parent visually but not in the DOM, causing unexpected clipping
- •overflow:hidden on body does not prevent scrolling if the html element can still scroll
When it happens
- •When adding overflow:hidden to a layout container to fix a collapsed parent after floats
- •When a sticky sidebar stops sticking after wrapping it in a scrollable or clipped container
- •When adding drop shadows to cards inside a carousel or slider with overflow:hidden
- •When a CSS animation moves an element outside its parent bounds and it disappears mid-animation
- •When a horizontal scroll container is created with overflow-x:hidden but unintended vertical scroll appears
Examples and fixes
overflow:hidden on the parent clips the card's box-shadow before it renders outside the border box.
Clipped box-shadow on a card inside a container
❌ Wrong
/* Parent clips child's shadow */
.card-list {
overflow: hidden;
padding: 8px;
}
.card {
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 16px;
}✅ Fixed
/* Use clip-path instead — does not clip overflow effects */
.card-list {
clip-path: inset(0);
padding: 16px; /* Extra padding gives shadow room */
}
.card {
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 16px;
}overflow:hidden paints nothing outside the element's border box, including box-shadow which renders as an outer decoration. Adding padding to the container gives the shadow room before clip-path or overflow:hidden cuts. Alternatively, remove overflow:hidden and use clip-path:inset(0) which clips the visual box but does not create a block formatting context and does not affect CSS shadow rendering the same way. The cleanest fix is often to add enough padding to the container so the shadow is still within the clipping boundary.
A sticky sidebar stops sticking when any ancestor has overflow:hidden applied.
position:sticky broken by overflow:hidden ancestor
❌ Wrong
/* overflow:hidden on ancestor breaks sticky */
.layout {
overflow: hidden; /* Used to contain floats */
}
.sidebar {
position: sticky;
top: 24px;
/* Sticky never activates — layout clips scroll context */
}✅ Fixed
/* Remove overflow:hidden from scroll ancestors of sticky elements */
.layout {
/* Use a clearfix or display:flow-root instead */
display: flow-root; /* Contains floats without overflow:hidden */
}
.sidebar {
position: sticky;
top: 24px;
/* Now sticky works correctly */
}position:sticky requires that its scroll container — the nearest ancestor that scrolls — does not clip overflow. When any ancestor has overflow:hidden, overflow:auto, or overflow:scroll, it becomes the sticky element's scroll container. A clipping scroll container causes sticky to behave as if scroll never occurs, so the element stays in its normal document position. The fix is to remove overflow:hidden from ancestors that contain sticky elements. Use display:flow-root to contain floats without creating a clipping boundary, or use a pseudo-element clearfix hack instead.
Setting overflow-x:hidden on body forces overflow-y to become auto, allowing unexpected vertical scroll on html.
overflow-x:hidden creates unintended vertical scroll
❌ Wrong
/* Trying to hide horizontal scroll — triggers vertical scroll bug */
body {
overflow-x: hidden;
/* overflow-y becomes auto implicitly */
}
html {
/* html element can still scroll vertically — body scroll is disabled */
}✅ Fixed
/* Set overflow on both html and body, or use clip-path */
html, body {
overflow-x: hidden;
}
/* Or use a wrapper div with clip-path for horizontal containment */
.page-wrapper {
clip-path: inset(0);
overflow-x: hidden;
}When overflow-x and overflow-y are set independently, the browser forces the other axis to auto if one axis is hidden and the other is visible — because two orthogonal overflow axes cannot independently be visible and hidden at the same time. Setting overflow-x:hidden on body makes overflow-y auto, and since html can still scroll, vertical scrolling moves to the html element instead of body. This breaks JavaScript scroll event listeners attached to body. Fix by applying overflow-x:hidden to both html and body, or use clip-path:inset(0) on a wrapper element for horizontal clipping without the two-axis interaction.
What overflow:hidden actually does to layout
overflow:hidden performs two distinct functions simultaneously, and understanding both is essential for diagnosing side effects. The first function is content clipping: any visual content that extends beyond the element's border box is painted off-screen and invisible to the user. This includes child element content, box-shadow decorations, outline rings, and transformed positions. The second function is establishing a block formatting context (BFC).
A block formatting context is a self-contained layout region where floats are contained, margins do not collapse across the BFC boundary, and the element's height includes floated children. overflow:hidden was historically the most common way to trigger a BFC for float containment. display:flow-root was introduced specifically to trigger a BFC without the clipping side effect, but it arrived late and many codebases still use overflow:hidden for this purpose.
The clipping boundary is the border edge — the outer edge of the border, not the padding edge or content edge. A child element with box-shadow: 0 8px 16px black extends visually outside the border edge (shadows are rendered outside the box model). overflow:hidden clips at the border edge, cutting the shadow. Adding padding to the parent element moves content inward but does not change where clipping occurs — you need to add padding equal to the shadow spread to give the shadow room before the clip.
For outline, the situation is the same — outline renders outside the border edge and is clipped. For border-radius combined with overflow:hidden, the clipping follows the rounded corners, which is the intended use case for clipping avatars and thumbnails to circular or rounded shapes. This specific use of overflow:hidden is reliable and has no unintended side effects.
Finding the overflow source in DevTools
Open Chrome DevTools and use the Layout panel or Elements panel to identify which ancestor element has overflow:hidden. In the Elements panel, select the element that is clipped or broken, then use the Styles tab to search for overflow rules on parent elements. You can also click the parent element in the DOM tree and check its Computed tab for the overflow property value.
Chrome DevTools also has a built-in overflow indicator. Open DevTools, go to the Layout panel in the sidebar, and look for the Overflow badge on elements in the DOM tree. Elements with overflow:hidden, overflow:auto, or overflow:scroll display a badge that you can click to scroll the element into view and select it.
For position:sticky debugging, the Elements panel in Chrome shows a Sticky badge next to sticky elements. If the badge is greyed out, sticky is not active. The most common reason is that an ancestor has an overflow value other than visible. Inspect ancestors one by one, checking the overflow property in the Computed tab, until you find the culprit.
For clipped shadows and outlines, temporarily add a bright color border to the affected element and increase the parent's padding in DevTools. If the border appears but the shadow still does not, the shadow is being clipped. Calculate the shadow's total spread (blur radius + spread radius) and add that as padding to the container, or switch from overflow:hidden to clip-path:inset(0) on the parent.
For the overflow-x:hidden body bug, open the Console and run document.documentElement.scrollTop to check if the html element is scrolling. If it returns a non-zero value while the page appears to scroll normally, the vertical scroll is attached to html instead of body.
Targeted fixes for overflow clipping problems
To contain floats without clipping children, replace overflow:hidden with display:flow-root. This is the modern, purpose-built property for establishing a BFC. It is supported in all modern browsers. For environments that must support very old browsers, a ::after clearfix (content: ''; display: table; clear: both) works without any overflow or BFC implications.
To fix a broken position:sticky, find every ancestor of the sticky element and check its overflow property. Any value other than visible (including hidden, auto, or scroll) creates a scroll container for the sticky element. Remove the overflow property from those ancestors or restructure the HTML so the sticky element's scroll container is the page itself.
To clip content without breaking box-shadow or sticky, use clip-path:inset(0) instead of overflow:hidden. clip-path:inset(0) clips the painted area of the element to its border box but does not create a BFC, does not affect overflow-y, and does not alter the scroll container chain for sticky elements. It clips box-shadow just as overflow:hidden does, but it is preferable when you need clipping without BFC side effects.
For horizontal-only clipping without the overflow-y:auto forced value, apply overflow-x:hidden to both the html and body elements. This prevents the axis-interaction bug where body gets overflow-y:auto and scroll migrates to html. Alternatively, use a wrapper div with overflow-x:hidden instead of applying it to body, which avoids the html/body propagation rules entirely.
For rounded avatar clipping with box-shadow, apply overflow:hidden and border-radius to the image container, and apply box-shadow to an outer wrapper. This separates clipping from decoration: the inner element clips the image to the circle shape, and the outer element renders the shadow without being clipped.
Overflow edge cases on mobile and with transforms
CSS transform on an ancestor creates a containing block for fixed-position descendants but does not affect overflow:hidden clipping in the same way. An element with transform:translate() and overflow:hidden will clip its children at the transformed position, not the original document position. This catches developers by surprise when animation moves an element partially outside its transformed parent.
On iOS Safari, overflow:hidden historically did not prevent scrolling inside elements that had -webkit-overflow-scrolling:touch applied. The modern replacement is overscroll-behavior, which controls whether scroll reaches parent containers. Setting overscroll-behavior:contain on a scrollable inner container prevents scroll chaining to parent containers without relying on the old -webkit property.
overflow:hidden on body does not reliably prevent page scrolling in all browsers. On iOS, the body element's scroll can be suppressed with overflow:hidden but the user can still drag the page in some contexts. The reliable solution for preventing page scroll (for modal dialogs, for example) is to apply overflow:hidden to the html element as well, and to save and restore scrollTop on show/hide.
In older Android WebViews, overflow:hidden combined with position:absolute children occasionally caused layout calculation bugs where the child was positioned relative to the scroll position rather than the element's top-left corner. This was a browser bug, not a CSS error. If you encounter this, test without overflow:hidden to confirm, then apply a translate3d(0,0,0) hack on the child or restructure the DOM.
CSS Grid and Flexbox children can overflow their parent even when the parent has overflow:hidden if the child has a min-width or min-height that exceeds the available space. Grid and flex items respect their minimum content size by default. Adding min-width:0 or min-height:0 to the child allows it to shrink below its content size, preventing overflow before the clipping occurs.
Recurring mistakes with overflow:hidden
The most common mistake is using overflow:hidden as the first tool for any layout containment problem. Before reaching for it, ask whether you need clipping, float containment, or scroll control — these are three different problems with different ideal solutions. display:flow-root for floats, overflow:auto or overflow:scroll for scroll containers, and clip-path for pure visual clipping.
Applying overflow:hidden to a layout wrapper that contains a sticky navigation or sidebar is extremely common in component-based UIs where the outer wrapper is written by one team and the inner sticky component by another. Document which elements must not have overflow set for sticky behaviour to work. A code comment in the parent component explaining this dependency prevents future breakage.
Using overflow:hidden to hide a dropdown menu, tooltip, or popover that extends outside a parent card. These elements should be positioned relative to the viewport or a portal at the document body level, not clipped by their card container. React portals, Angular CDK Overlay, and native popover API exist specifically for this use case.
Setting overflow:hidden on both the inner and outer scroll containers when building a split-pane layout. Only one element in the scroll chain should clip — the outermost scroll container. Inner elements should use overflow:visible or match the scroll direction of the outer container without crossing overflow values.
Ignoring the padding requirement when clipping shadows. Developers add overflow:hidden to a card list container and then wonder why card shadows are cut off. The fix of adding padding equal to the shadow extent is correct but frequently overlooked. An alternative design pattern is to not clip the card list at all and rely on the viewport edge for natural containment.
Safe overflow patterns for modern layouts
Prefer display:flow-root over overflow:hidden for float containment. It is the semantically correct property for this use case, produces no clipping, and does not affect sticky descendants. Paired with the ::after clearfix for legacy browser support, you can have clean float containment across a wide browser range.
For horizontal scroll containers like carousels and image galleries, use overflow-x:auto combined with white-space:nowrap or flexbox with flex-wrap:nowrap. This creates a scrollable region without the two-axis interaction problem of overflow-x:hidden. Users on mobile can swipe horizontally, and keyboard users can tab through items.
For clipping images to rounded or circular shapes, overflow:hidden with border-radius is the correct and only reliable approach. This specific pattern has no problematic side effects and is universally used. Wrap the image in a container div, apply the border-radius and overflow:hidden to the container, and apply box-shadow to a separate outer wrapper if a shadow is needed.
Document scroll-related overflow rules in component interfaces. If a component requires its scroll ancestor to have overflow:visible — a common requirement for sticky headers and drop-down menus — document this with a comment or a storybook story that demonstrates the correct wrapping context.
Audit overflow values when integrating third-party components. Many UI libraries apply overflow:hidden to scroll containers, which can break sticky elements in your application when you embed them in library wrappers. Inspect the rendered DOM in DevTools and trace sticky failures to unexpected overflow values in library-generated markup.
Consider contain: paint as a modern alternative to overflow:hidden when the goal is purely visual clipping. Setting contain: paint on an element clips its painted output to its border box without creating a scroll container, which means position:sticky descendants continue to function correctly. One important caveat is that contain: paint causes any position:fixed children of the element to be positioned relative to the element rather than the viewport, so it shares that side effect with CSS transforms and should be applied with the same caution.
overflow:hidden debug checklist
- ✓Check all ancestors of a broken sticky element for overflow values other than visible
- ✓Use display:flow-root instead of overflow:hidden to contain floats
- ✓Add padding equal to shadow extent when overflow:hidden clips box-shadow
- ✓Apply overflow-x:hidden to both html and body to prevent the vertical scroll bug
- ✓Use clip-path:inset(0) when you need clipping without BFC or scroll side effects
- ✓Apply shadow to an outer wrapper if the inner container needs overflow:hidden for border-radius
- ✓Test overflow:hidden hidden:auto interactions on iOS Safari with real devices
- ✓Add min-width:0 to flex or grid children that overflow their containers unexpectedly
Related guides
Frequently asked questions
Why does overflow:hidden break position:sticky?
position:sticky requires a scrollable ancestor — an element whose overflow is visible or whose scroll is handled by the browser. overflow:hidden, overflow:auto, and overflow:scroll all create a scroll container. When the sticky element's nearest scroll container has overflow:hidden, scroll never occurs within that context, so sticky never activates. Remove overflow:hidden from ancestors of sticky elements and use display:flow-root instead for float containment.
Why is my box-shadow clipped when using overflow:hidden?
box-shadow renders outside the element's border box — it is an outer decoration. overflow:hidden clips everything outside the containing element's border edge. The shadow is painted in that outside region and is therefore clipped. To fix it, add padding to the parent element equal to the shadow's total extent (blur + spread), or use clip-path:inset(0) on the parent instead, or apply the shadow to an outer wrapper element that does not have overflow:hidden.
What is the difference between overflow:hidden and clip-path:inset(0)?
Both clip content to the border box, but they have different side effects. overflow:hidden creates a block formatting context (contains floats, prevents margin collapse), affects scroll container chains for sticky elements, and forces overflow-y to auto when overflow-x is set independently. clip-path:inset(0) only clips the painted area — it does not create a BFC, does not affect sticky behaviour, and does not trigger the two-axis overflow interaction. Use clip-path when you need visual clipping without layout side effects.
Why does overflow-x:hidden create a vertical scrollbar?
The CSS specification states that overflow-x and overflow-y cannot independently be visible and hidden at the same time. Setting overflow-x:hidden forces overflow-y to auto. On the body element, this auto value and the html/body scroll propagation rules cause vertical scroll to migrate to the html element instead of body, which can break JavaScript scroll event listeners. Fix by setting overflow-x:hidden on both html and body, or use a wrapper div instead of targeting body.
Can overflow:hidden on body prevent page scrolling?
Partially. Setting overflow:hidden on body alone is not reliable across all browsers and devices. iOS Safari in particular can still allow scroll gestures in some contexts. The reliable pattern for locking scroll is to set overflow:hidden on both the html and body elements and to save the current scrollTop value before locking, then restore it on unlock — otherwise the page jumps to the top when overflow:hidden is removed.
How does overflow:hidden affect CSS animations?
If a CSS animation moves an element outside its parent's border box during the animation, and the parent has overflow:hidden, the element is clipped at the boundary. This is often unintentional — the developer expects the element to animate freely. To allow animated elements to move outside their parent, remove overflow:hidden from the parent and use clip-path on an outer wrapper if containment is still needed, or redesign the animation to stay within the container bounds.
What is a block formatting context and why does overflow:hidden create one?
A block formatting context (BFC) is a self-contained layout region in CSS. Inside a BFC, floated elements are fully contained, margin collapse does not cross the boundary, and the element's height stretches to include its floated children. overflow:hidden creates a BFC as a side effect of establishing a new painting context. display:flow-root was later added to the spec specifically to create a BFC without any overflow, clipping, or painting side effects.
How do I clip a card's rounded corners without breaking shadows on its children?
Apply overflow:hidden and border-radius to an inner wrapper around the card image or content that needs clipping, and apply box-shadow to an outer wrapper that does not have overflow:hidden. This separates the clipping context from the shadow-rendering context. The outer element renders the shadow without interference, and the inner element clips the image or content to the rounded shape. This two-layer pattern is the standard approach for shadow plus border-radius combinations.
Does overflow:hidden affect how z-index and stacking contexts work?
overflow:hidden itself does not create a stacking context. However, elements with position:relative, position:absolute, or position:fixed combined with a z-index value do create stacking contexts, and these are independent of overflow. An absolutely positioned child with a high z-index inside an overflow:hidden parent will still be clipped by the parent's overflow boundary, even if the child is on top in the stacking order. Clipping is determined by overflow, not by z-index or stacking context.
All tools run in your browser. Your data never leaves your device. Last updated: 2026-05-06.