contain
A performance property: it promises the browser that changes inside this element cannot affect anything outside it, which lets the engine stop layout and paint work at the element boundary. ctnp applies paint containment, ctnst applies strict containment.
Class List
| Class | CSS | Description |
|---|---|---|
ctnn | contain: none | No containment (default) |
ctnc | contain: content | layout + paint containment |
ctns | contain: size | Size containment (children do not affect parent size) |
ctnl | contain: layout | Layout containment |
ctnp | contain: paint | Paint containment (children are not drawn outside boundaries) |
ctnst | contain: strict | size + layout + paint strict containment |
Live Demo
Containment is mostly invisible, with one exception: paint. The two boxes and their oversized children are identical in size and position and differ by a single class.
none — ctnn
The child spills out of the box exactly as usual.
paint — ctnp
The child is clipped at the padding box edge.
<!-- Identical boxes and identical oversized children -->
<div class="w100p h10rem br8px bg18181B ctnn">
<div class="w150p h6rem mt6rem ml4rem bg6366F1 br8px"></div>
</div>
<div class="w100p h10rem br8px bg18181B ctnp">
<div class="w150p h6rem mt6rem ml4rem bg38BDF8 br8px"></div>
</div>Class Details
ctnncontain: none
The default: no containment at all. Use it explicitly to opt one instance out of a containment class applied by a shared component.
<!-- Explicitly opt an element out of an inherited containment class -->
<div class="ctnn">
Nothing is contained here.
</div>ctnlcontain: layout
Declares that the internal layout cannot influence layout outside. However the children rearrange, siblings and ancestors are never re-laid out. In exchange the element becomes a containing block and a stacking context, and margins no longer collapse through it.
<!-- The internal layout of this widget can never move anything outside it -->
<div class="ctnl p2rem bg18181B br8px">
<p>Rearranging children re-lays out only this box.</p>
</div>ctnpcontain: paint
Declares that descendants never paint outside the padding box. Visually the result resembles overflow: hidden, but the point is to let the browser skip painting the subtree entirely when it is off screen. It also brings the side effects of layout containment.
<!-- Nothing inside can paint outside the padding box -->
<div class="ctnp h10rem br8px bg18181B">
<div class="w32rem">This wide child is clipped.</div>
</div>ctnscontain: size
Stops children from contributing to the element's size. The browser sizes the box without looking at its content, so without an explicit height the box collapses to zero. This is the most dangerous of the four values.
<!-- The box must carry its own dimensions -->
<div class="ctns h20rem w100p bg18181B br8px">
<p>Content no longer contributes to the size.</p>
</div>Always pair it with an explicit size
Size containment needs a width and height, or an aspect-ratio, alongside it. Otherwise the element simply appears to vanish.
ctnccontain: content
Turns on layout, paint, and style containment at once, and is the sensible default in practice. Size containment is deliberately excluded, so the content still determines the height. Safe for cards, widgets, and comment items whose height varies.
<!-- Independent card widget: layout + paint + style -->
<div class="ctnc p2rem bg18181B br8px">
<h3>Widget title</h3>
<p>Changes to this card do not affect the outside.</p>
</div>ctnstcontain: strict
Everything content does, plus size containment. It is the fastest option because the browser can skip an off-screen subtree wholesale, but you must supply the dimensions yourself, so keep it for cases like fixed-height list rows.
<!-- Fully isolated: size + layout + paint + style -->
<div class="ctnst h10rem oh">
<p>The browser can skip this subtree entirely when off screen.</p>
</div>Practical Example
<!-- Independent card widget -->
<div class="ctnc p2rem bg18181B br8px">
<h3>Widget title</h3>
<p>Changes to this card do not affect the outside.</p>
</div>
<!-- Long list item requiring performance optimization -->
<div class="ctnst h10rem oh">
<p>Fully isolated element</p>
</div>A long list of uniform-height rows is the textbook use case for strict containment.
<!-- Feed of a few thousand rows. Each row is a fixed height,
so size containment is safe and the browser can skip
layout and paint for everything scrolled off screen. -->
<ul class="lsn p0 m0">
<li class="ctnst h8rem df aic gap16px px16px bb1pxsolid27272A">
<img src="/avatar.jpg" class="w4rem h4rem br50p" alt="" />
<div>
<p class="fs14px cFAFAFA fw600">Row title</p>
<p class="fs12px c71717A">Secondary line</p>
</div>
</li>
<!-- ... a few thousand more ... -->
</ul>
<!-- Third-party embed: keep its layout from disturbing the page -->
<div class="ctnc br8px oh b1pxsolid27272A">
<iframe src="https://example.com/embed" class="w100p h30rem bn"></iframe>
</div>When to Use What?
| Situation | Recommended |
|---|---|
| Independent widget/card | ctnc |
| Off-screen element optimization | ctnst |
| overflow: hidden alternative | ctnp |
| Prevent layout recalculation | ctnl |
Tips and Pitfalls
It is a performance tool, not a layout tool
Reaching for ctnp because you want clipping is the wrong instinct; overflow is the property for that. Containment is what you deploy against a measured performance problem. Sprinkled everywhere, it mostly produces surprising layout changes.
It breaks sticky and fixed descendants
Layout and paint containment create a new containing block. A position: fixed descendant then anchors to this box instead of the viewport, and a sticky header cannot escape it, so it looks like sticky stopped working.
Dropdowns and tooltips get clipped
Menus, tooltips, and popovers opened inside a paint-contained card are cut off at its edge. Do not apply ctnp, or the values that include it such as ctnc and ctnst, to containers that host such UI.
Contained boxes affect scroll anchoring and measurement
An element with size containment is measured as if it had no content, so late-arriving content can make the scroll position jump, and off-screen elements can report a size of zero.
content-visibility is often the better choice
If the goal is to skip rendering off-screen content, content-visibility: auto applies the containment it needs on its own and accepts a size hint. That is safer than hand-rolling strict containment.