What do the CSS `contain` property and `content-visibility: auto` promise the browser's layout engine, and what do you give up in exchange?
answer
- a promise the engine can act on
- layout, paint, size, style
- containment brings side effects with it
- skipped content needs a guessed size
- auto stays findable, hidden does not
basics
~20 sCSS containment promises that an element's internals cannot affect the rest of the page, so layout can stop at its boundary. content-visibility: auto goes further and skips off-screen subtrees entirely, at the price of guessed sizes, scroll-position accuracy and some side effects on positioning and clipping.
solid answer
~50 s`contain` is a promise you make to the engine so it can skip work. `contain: layout` isolates the element's internal layout from the outside; `contain: size` says its own size is computed as if it had no contents; `contain: paint` clips descendants to its padding box; `contain: style` scopes counters and quotes. `content` is the shorthand for everything except size containment, and `strict` adds size on top. The promises are not free: layout and paint containment make the element an independent formatting context, a stacking context and a containing block for absolutely and fixed-positioned descendants, so an existing layout can shift when you add them. Size containment collapses the element unless you supply `contain-intrinsic-size`. `content-visibility: auto` applies containment and, while the element is off-screen and not relevant to the user, skips rendering its contents entirely — so scrollbar length and scroll positions depend on how good your `contain-intrinsic-size` estimate is.
code
css · 14 lines.feed-item {
content-visibility: auto;
contain-intrinsic-size: auto 180px;
}
.editor-pane {
contain: content; /* layout + paint + style, no size containment */
}
.fixed-panel {
contain: strict;
width: 320px;
height: 480px;
}go deeper
Know that CSS containment exists as a way to tell the browser a component is independent so it can skip work, and that content-visibility: auto lets a browser avoid rendering off-screen sections. Naming the idea is enough here.
Distinguish the containment types — layout, paint, size, style — and know that content and strict are shorthands differing over size containment. Be ready to explain why size containment needs contain-intrinsic-size to avoid a collapsed box.
Talk about the side effects you would check before shipping it: new containing block for fixed descendants, new stacking context, paint clipping, and scroll-position accuracy when estimates for skipped content are wrong. Say how you would verify a real win.
Decide where this belongs in the system. Containment is a contract about component independence, so it pays off when components are genuinely isolated; weigh it against content-driven sizing, and require measurement before it becomes a default in a shared component library.
## The bargain Layout is expensive because in general the engine cannot know whether a change inside a subtree affects the outside — an auto-height parent depends on its children, a wide cell resizes a table, overflowing content reaches ancestors. CSS containment lets you assert that it does not, and having that assertion, the engine can bound its work. ## The containment types - **`contain: layout`** — the element's internal layout is isolated: nothing inside can affect the geometry of boxes outside, and outside boxes cannot reach in. The element establishes an independent formatting context (so floats and margins do not cross it), becomes a stacking context, and becomes the containing block for `position: absolute` and `position: fixed` descendants. - **`contain: size`** — the element is sized as if it had no contents. Its own dimensions no longer depend on what is inside, which is the strongest possible cut in the dependency chain. Without an explicit size or `contain-intrinsic-size`, it collapses to zero in the contained dimension. - **`contain: inline-size`** — size containment on the inline axis only, so the element still grows in the block direction from its content. This is the well-behaved variant, and the same machinery underpins container queries. - **`contain: paint`** — descendants are clipped to the element's padding box and nothing paints outside it. Also creates a stacking context, an independent formatting context, and a containing block for positioned descendants. Off-screen contained elements need not be painted at all. - **`contain: style`** — scopes counter and quote effects so they cannot escape the subtree. Two shorthands: `content` applies layout, paint and style containment (everything except size), and `strict` adds size containment as well. `content` is usually what you want, because size containment is the one that needs a size supplied. ## content-visibility `content-visibility: auto` builds on containment: the element applies layout, style and paint containment, and while the browser decides its contents are not relevant to the user — far off-screen — it also applies size containment and **skips rendering the contents entirely**: no layout, no paint for the subtree. Scroll it into view and rendering resumes. `content-visibility: hidden` skips the contents unconditionally, like `display: none` for the subtree, while keeping its rendering state so re-showing is cheap. The partner property is `contain-intrinsic-size`, the placeholder size used while contents are skipped: ```css .row { content-visibility: auto; contain-intrinsic-size: auto 120px; /* remember the real size once measured */ } ``` The `auto` keyword tells the browser to remember the last actually-rendered size and use that instead of the guess once it has one. As of 2026 `content-visibility` is available across the major engines — Chromium shipped it in 2020, Firefox and Safari during 2024 — so the historical caveat is about older browsers, where it degrades to rendering everything. ## What it costs you **Layout surprises.** Adding `contain: layout` or `paint` to an existing component is not visually neutral: becoming a containing block re-anchors `position: fixed` descendants (a modal inside now pins to the panel, not the viewport), becoming a stacking context changes what can paint above what, and paint containment clips a dropdown that used to overflow. **Collapsed boxes.** Size containment without `contain-intrinsic-size` gives you a zero-height element, which is the most common first encounter with `contain: strict`. **Scroll accuracy.** With `content-visibility: auto`, the scrollbar length is computed from estimates for everything not yet rendered. Bad estimates make the scrollbar and scroll position shift as content is realised, and jumping to the bottom of a long list can land in the wrong place. **Findability.** Content skipped by `content-visibility: auto` remains reachable — find-in-page, focus navigation and accessibility make a subtree relevant to the user, which forces it to render. Content under `content-visibility: hidden` does not; treat it as hidden in every sense. ## Choosing Apply containment where a component is genuinely self-contained and mutates a lot — a chat pane, a virtualised table body, an editor canvas. Prefer `content` over `strict` unless you can state a size. Use `content-visibility: auto` for long, homogeneous lists whose row height you can estimate, and measure: on short pages the bookkeeping can cost more than it saves.
- Why does adding `contain: paint` to a card sometimes break a dropdown inside it?Paint containment clips descendants to the element's padding box and makes it a containing block for absolutely and fixed-positioned descendants. A dropdown that used to escape the card and overflow outside it now has both a new containing block and a clip edge, so it is cut off at the card boundary.
- An element with `contain: strict` collapses to zero height. What is happening and how do you fix it?`strict` includes size containment, so the element is sized as if it had no contents and the block dimension falls to zero unless something else supplies it. Either give it an explicit size, drop to `contain: content` which omits size containment, or supply `contain-intrinsic-size` as the placeholder the engine should use.
- Is text inside a `content-visibility: auto` subtree reachable by find-in-page?Yes. Being searched for, focused or reached by assistive technology makes a subtree relevant to the user, and the browser then renders it and scrolls to it. That is the practical difference from `content-visibility: hidden`, whose contents stay skipped and unreachable until you change the value.
saying these in an interview costs you the question
- Calls contain a pure optimisation with no visual effect
- Uses contain: strict without contain-intrinsic-size
- Thinks content-visibility: auto hides content from search
- Confuses paint containment with overflow: hidden semantics
- Applies containment everywhere without measuring