CSS Containment: The contain Property Explained
The CSS contain property tells the browser an element's layout, paint, or size won't affect the rest of the page — unlocking safe, targeted rendering shortcuts.
The contain CSS property tells the browser that a given element’s internal layout, styling, size, or paint is isolated from the rest of the page — so a change inside that element can’t affect anything outside its box. That promise matters because it’s the difference between a browser doing a small, local recalculation and doing a full-page one: without containment, the browser has to assume any change anywhere might ripple outward, and it has to check.
Why the browser needs the hint
By default, nothing in the DOM is isolated. If a paragraph’s text grows and pushes its container taller, that change can shift every element below it on the page — the browser has no way to know in advance whether a given element’s size, appearance, or content depends on something happening elsewhere. So on every update, it conservatively recalculates far more of the page than strictly necessary, because ruling out side effects is more expensive than just doing the work.
contain lets you tell the browser, explicitly, “this box’s internals stay inside this box.” Once that’s declared, the browser can treat the contained element as a self-sufficient unit: recalculate what’s inside it without touching layout or paint for the rest of the page. This is the same mechanism that makes content-visibility able to skip rendering work for off-screen content — content-visibility: auto works specifically because it applies containment underneath, which is what makes it safe for the browser to defer that work in the first place.
The individual containment types
contain accepts several keywords, and they can be combined:
.widget {
contain: layout;
}
.card {
contain: layout paint;
}
.strict-box {
contain: strict; /* shorthand for layout + style + paint + size */
}
| Value | What it isolates |
|---|---|
layout | The element’s internal layout doesn’t affect layout outside it — floats, margins, and positioning inside stay contained |
paint | Descendants are clipped to the element’s bounds; nothing inside can paint outside it (also creates a containing block for absolutely positioned descendants) |
size | The element’s size is computed without looking at its children’s content — you must supply the size another way, or it collapses to zero |
style | Counters and quotes don’t leak out of the element’s subtree |
content | Shorthand for layout paint style together |
strict | Shorthand for layout paint style size — the strongest guarantee, but requires you to size the element explicitly |
layout and paint are the two that matter most for performance, since they’re what let the browser skip recalculating the rest of the page when something changes inside a contained box. style containment is narrower and mostly relevant if you’re using CSS counters — it stops a counter inside the contained element from affecting counters outside it, which is a fairly specialized concern but a real footgun without containment if you’re generating numbered sections dynamically.
The catch with size containment
size containment is the one that most often surprises people. It tells the browser to size the element without looking at its content — which is exactly what makes layout containment reliable, since the browser needs to know the element’s size before it can guarantee that internal layout won’t affect anything outside. But if you apply size containment without also giving the element an explicit height (or using contain-intrinsic-size, the same property content-visibility relies on), the element collapses to zero size, because its content is exactly what would normally determine that size and containment has told the browser to ignore it.
.contained-card {
contain: strict;
contain-intrinsic-size: auto 400px;
}
This is the same trap content-visibility: auto guards against with contain-intrinsic-size — if you reach for size or strict containment directly rather than through content-visibility, you need to handle that sizing hint yourself.
Where it actually pays off
Containment is most valuable on independent, repeated UI units where changes are genuinely local: cards in a grid, list items in a feed, widgets on a dashboard, chat messages in a scrolling log. Any component where updating one instance — say, a like count ticking up on a single card — has no business affecting the layout of any other card is a good candidate. Declaring contain: layout paint (or contain: content for the common case) on the repeated unit lets the browser scope its recalculation work to that one instance instead of re-checking siblings and ancestors, which adds up fast on pages with hundreds of similar elements.
It’s a natural pairing with container queries, since a container query already implies the element being queried is a self-contained layout unit that responds to its own size — the containment model and the container-query model are built on the same underlying idea of a box that manages its own internals.
What it doesn’t do
contain is a rendering-performance hint, not a layout tool — it doesn’t change how an element is positioned, sized by default, or styled visually. It also doesn’t fix layout problems caused by something other than expensive recalculation; if a page is slow because of network-bound image loading rather than layout thrashing, containment won’t move the needle, and lazy-loading images is the relevant fix instead. And containment doesn’t isolate accessibility semantics or event handling — those keep working exactly as they would without it.
Support for contain is broad across modern evergreen browsers, and like most CSS containment features, applying it to a browser that doesn’t recognize a specific value degrades gracefully — the browser just renders without that optimization rather than breaking anything.
The takeaway
contain tells the browser that an element’s layout, paint, style, or size is self-contained, which lets it skip recalculating the rest of the page when something changes inside that element. layout and paint deliver most of the performance benefit; size containment requires an explicit size or the element collapses; and content-visibility builds on all of this to add the ability to skip rendering off-screen content entirely. On pages with many repeated, independent UI units, reaching for containment — directly or through content-visibility — is one of the more effective, low-risk levers for keeping the Core Web Vitals responsiveness metrics in check as a page grows.
Tagged
Keep reading
Takina · · 4 min read Variable Fonts Explained: One File, Every Weight
A variable font packs every weight, width, and style into a single file, controlled with CSS — cutting requests and enabling fluid typography.
Takina · · 5 min read CSS will-change Explained: Compositing and Performance
The CSS will-change property hints the browser to prepare an element for an upcoming change, moving it to its own compositor layer. When to use it and when not to.
Takina · · 4 min read font-display Explained: Controlling How Web Fonts Load
The CSS font-display property controls whether text waits for a web font or renders in a fallback first. Here's how swap, block, and optional differ.