in
• 13 minute learn
Written by Harry Roberts on CSS Wizardry.
View this web page as Markdown.
Desk of Contents
Unbiased writing is dropped at you by way of my fantastic
Supporters.
- Why Containment Exists
- Meet the
compriseProperty - Format Containment
- Paint Containment
- Measurement Containment
- Model Containment
- Particular Values:
content materialandstrict - Containment within the Actual World
content-visibilityandcontain-intrinsic-size- Caveats, Gotchas, and Issues to Look ahead to
- When to Use Containment
- Closing Ideas
Persevering with my work on net efficiency for design programs, I need to have a look at
a woefully underused CSS function known as
containment.
I worry it’s underused as a result of there isn’t a lot written about it, so this piece
goals to be the put up I want I’d been in a position to learn a number of years in the past. Hopefully it
demystifies issues just a little for you, too.
Trendy UIs are busy locations. A single web page would possibly comprise a set header, an
infinite scroll feed, a sticky cart abstract, and some completely different third-party
widgets caught across the edges. Each time one thing modifications, the browser wants
to determine how a lot of that web page it has to re-think: types, structure, portray,
compositing, and so forth.
Out of the field, the browser must be cautious. If it can’t make sure that
a change is native, it behaves as if virtually something might need moved, forcing it
to the touch extra of the web page than is strictly vital. Whereas that is protected, it’s
not at all times low-cost.
CSS containment is a method of telling the browser the place the boundaries actually are.
You utilize it to say this little bit of the DOM is unbiased of the remaining; you possibly can
. In return, the browser is free to skip
deal with it as a self-contained island
work outdoors these islands when issues change.
On this put up, we’ll check out what CSS containment really is, what every
comprise worth does, and easy methods to use it confidently on actual initiatives with out
creating hard-to-debug uncomfortable side effects. We’ll additionally have a look at my most favorite
real-world instance of simply how efficient containment could be. Let’s go!
I assist corporations discover and repair site-speed points. Efficiency audits, coaching, consultancy, and extra.
Why Containment Exists
To grasp containment, you don’t must memorise all the rendering
pipeline, however you do want a tough psychological mannequin of the place the work goes.
When one thing modifications within the DOM, a browser sometimes has to:
- recalculate types for affected parts,
- recalculate structure (sizes and positions),
- repaint the pixels that modified, and
- re-composite layers on display.
The costly half is commonly how far these modifications unfold. A small change in
one a part of the tree can invalidate structure or portray in different elements — and even
the entire doc — and the browser can’t at all times know that the impact is native.
That’s the reason comparatively easy operations on a big software can really feel
sluggish: the browser is having to consider the entire world.
Containment is a promise {that a} given subtree is remoted:
- modifications inside it won’t affect structure or paint outdoors it, and
- in some circumstances, its personal dimension doesn’t rely upon its kids.
When you make that promise, the browser can exploit it. For instance:
- it might probably keep away from relayout of the remainder of the web page when one thing modifications inside
a contained widget, or - it might probably skip portray descendants of an off-screen container totally.
All of that reduces work on the principle thread, which is strictly what we wish when
we try to maintain interactions snappy (assume Interplay to Subsequent
Paint).
Meet the comprise Property
The principle lever you’ll pull is the comprise property:
.card {
comprise: content material;
}
At a excessive degree, comprise enables you to assert completely different sorts of independence for
a component and its subtree. There are 4 primary sorts of containment:
You may specify them individually or in combos:
.card {
comprise: structure paint;
}
On prime of these, there are a few shorthand values:
content material: shorthand forstructure paint model.strict: shorthand fordimension structure paint model.
There’s additionally inline-size, which is a extra focused type of dimension
containment — we don’t actually need to present it far more consideration than that.
Let’s undergo every of those in flip.
Format Containment
comprise: structure tells the browser that the inner structure of the
aspect is totally unbiased of the remainder of the web page.
.card {
comprise: structure;
}
In observe, which means:
- structure calculations for descendants of
.carddon’t have an effect on structure
outdoors of.card, - the
.cardestablishes its personal formatting context (like a mini structure world), - floats and margin-collapsing are contained inside
.card, .cardturns into the containing block forplace: absoluteand
place: mounteddescendants, and- a brand new stacking context is created, so
z-indexon kids is scoped
to that card.
This has two foremost penalties:
- Efficiency. When one thing modifications inside
.card, the browser can maintain
most structure work native to that subtree as a result of it has been informed none of these
modifications affect different packing containers outdoors. - Format behaviour. The brand new formatting context and containing block could be
very helpful for controlling floats, margin-collapsing, andplace: mounted
kids, however it might probably additionally change behaviour in comparison with an uncontained
aspect.
A easy, real looking use case is a grid of dashboard playing cards:
.dashboard-card {
comprise: structure;
}
Every card might have its personal inside construction (headings, charts, small
controls), however nothing inside one card impacts the structure of some other. When
a chart animates inside a card, the browser doesn’t need to re-evaluate structure
for all the dashboard.
Gotchas
- A hard and fast-position little one that was anchored to the viewport will
now be anchored to the contained aspect as a substitute. If you’re utilizing
place: mountedfor tooltips or overlays, verify them fastidiously. - Margin-collapsing guidelines change; that’s often a function, however it might probably
have an effect on legacy layouts that depend on collapsing from the primary little one
into the guardian.
Paint Containment
comprise: paint isolates portray to the aspect’s field:
.card {
comprise: paint;
}
With paint containment in place:
- nothing inside
.cardcan visibly overflow its padding field, - if the
.carditself is off-screen, the browser doesn’t want to color its
kids in any respect, and - you continue to get a stacking context and containing block, as with structure
containment.
That is splendid for widgets the place every little thing ought to keep visually inside
the field anyway: playing cards, tiles, thumbnail previews, and so forth.
Gotchas
- Any intentional overflow results (drop-shadows that stretch past the field,
popovers that stick out of a sidebar, ornamental ‘bleeds’) merely won’t
present. In the event you rely upon overflow, don’t usecomprise: painton that aspect. - In the event you mix
structureandpaintcontainment, you will note each behaviours:
unbiased structure plus clipped portray.
Measurement Containment
comprise: dimension is extra specialised. It decouples a component’s dimension from its
contents:
.widget {
comprise: dimension;
}
While you activate dimension containment:
- the scale of
.widgetis calculated as if it had no kids, and - kids can nonetheless be laid out and painted inside, however they don’t inform the
container’s personal dimension.
This can be a highly effective constraint. Used wrongly, it’s also a simple strategy to
create a bunch of zero-sized packing containers.
In virtually all circumstances, if you use comprise: dimension you will need to additionally present an
specific dimension for the aspect, both by way of the same old width/peak properties
or by way of contain-intrinsic-size:
.widget {
comprise: dimension;
contain-intrinsic-size: 400px 300px; /* Fallback/reserved dimension */
}
The intrinsic dimension tells the browser what dimension to imagine for structure functions if
it can’t derive that dimension from the kids. This turns into notably
vital if you begin deferring rendering with content-visibility, which
we’ll have a look at shortly.
Gotchas
- Forgetting to set a dimension typically results in zero-height containers, which then
disguise their kids or trigger sudden scroll behaviour. - The scale containment itself doesn’t purchase you a lot efficiency by itself; it
is especially there to unlock different optimisations safely.
Model Containment
comprise: model might be the least glamorous of the 4, but it surely has
a particular job:
.part {
comprise: model;
}
Model containment stops sure style-related uncomfortable side effects from spreading
outdoors the contained subtree. The principle one you’ll encounter is CSS counters:
- Counters created or modified inside
.partwon’t have an effect on counters
outdoors it.
When you’ve got ever used automated numbering for headings or
figures
throughout a web page, you’ll know that counters are world by default. Model
containment is a method of claiming this part’s counters are its personal, don’t
.
allow them to leak out
It does not provide you with normal goal ‘scoped CSS’ within the sense of stopping
selectors from matching, so it shouldn’t be confused with Shadow DOM or
@scope.
Particular Values: content material and strict
Typing comprise: structure paint model again and again will get boring quick. The spec
subsequently provides us a few handy shorthands.
comprise: content material
.article {
comprise: content material;
}
content material is shorthand for:
.article {
comprise: structure paint model;
}
You get:
- unbiased inside structure,
- clipped portray inside the padding field, and
- counters and related model side-effects scoped to the subtree.
You don’t get dimension containment. That omission is deliberate: with out
dimension, the danger of making zero-sized packing containers is far decrease, which makes
comprise: content material protected to use fairly broadly.
This worth is a superb default for self-contained items like:
- weblog posts on an inventory web page,
- playing cards in a grid,
- rows in a knowledge desk,
- slides in a carousel…
…so long as nothing wants to increase outdoors of the bounds of them (e.g. tooltips
in mentioned information desk).
comprise: strict
.panel {
comprise: strict;
contain-intrinsic-size: 600px 400px;
}
strict is shorthand for:
.panel {
comprise: dimension structure paint model;
}
That is essentially the most aggressive containment you possibly can ask for: the panel’s dimension no
longer will depend on its kids, its inside structure is unbiased, its paint is
clipped, and its counters are native.
That mixture could be very highly effective, but it surely comes with obligations:
- it is advisable give the panel an specific or intrinsic dimension,
- it is advisable be assured that nothing contained in the panel is supposed to
overflow visually, and - it is advisable perceive that
place: mountedkids will now anchor to the
panel, not the viewport.
As a rule of thumb: don’t attain for strict till you’ve got a transparent purpose and
a great understanding of what’s going to occur.
I assist corporations discover and repair site-speed points. Efficiency audits, coaching, consultancy, and extra.
Containment within the Actual World
Up to now we now have stayed pretty summary. Allow us to begin with an actual instance earlier than
we have a look at a number of extra generic patterns.
OpenTable’s Cell Drawer
A few years in the past, I ran a customized INP workshop for the
fantastic OpenTable (actually, web-perf and grub,
are you able to consider a greater consumer?!). Once we take into consideration INP, we often assume
of JavaScript, however the Presentation Delay part touches a whole lot of what I name
purple time: recalc model and structure. And whereas the headline financial savings beneath
aren’t going to win me any awards, I do assume it is a superbly succinct and
complete demonstration of comprise in motion…
On OpenTable’s cell UI, there’s a language switcher of their off-screen drawer
menu. Tapping the switcher opens a dropdown. The dropdown opens and pushes
content material beneath it down the viewport, but it surely doesn’t have an effect on something outdoors
of the drawer menu itself. With out comprisement, opening the language switcher
scopes a structure occasion to the entire doc, touching 4,371 nodes and making use of
new structure to only 41 of them — fewer than 10%:

#doc, touching 4,371 nodes to relayout simply 41. View full dimension/high quality (1MB)Whereas the entire operation solely took 11 milliseconds, that’s nonetheless a whole lot of
waste, and we don’t like waste.
By making use of comprise: strict to the drawer menu’s root DOM node, we will restrict
the attain of the work and create unbelievable financial savings:

Now, we will see as clear as day that the operation solely touched 73 DOM nodes, 40
of which wanted consideration, and the scope of the work could be very clearly the drawer
itself. Hyper exact, and about six occasions sooner.
I believe this is without doubt one of the most lovely demos I’ve ever been lucky
sufficient to current: such a narrative informed in a single earlier than/after.
If this type of rendering and interplay work appears acquainted, it’s precisely the
type of factor I cowl in workshops, masterclasses,
and hands-on consultancy.
Different Good Candidates
When you begin searching for them, you will note these alternatives in every single place:
- dashboards filled with unbiased playing cards, the place updates in a single card shouldn’t
power relayout of its neighbours, - lengthy, scrollable feeds or search outcomes, the place every merchandise could be handled as
its personal island, and - third-party widgets, the place you might not management the internals however can nonetheless
certain their impact on the remainder of the web page.
In these sorts of interface, comprise: content material is commonly an excellent beginning
level:
.dashboard-card,
.feed-item {
comprise: content material; /* structure + paint + model */
}
And the place it is advisable fence off an embed or advert slot extra explicitly, that is
typically sufficient:
.ad-slot {
comprise: structure paint;
}
If these widgets stay on different origins, it’s also price configuring your
preconnections correctly.
content-visibility and contain-intrinsic-size
Whereas this put up is about comprise, it might be unwise to not point out two
intently associated options: content-visibility and contain-intrinsic-size.
Skipping Work with content-visibility
content-visibility permits the browser to skip structure and portray work
for parts that aren’t at the moment related to the person, sometimes
as a result of they’re off-screen.
The worth you will note most frequently is auto:
.article-preview {
content-visibility: auto;
contain-intrinsic-size: 600px 400px;
}
With this in place:
- parts close to or contained in the viewport are rendered usually,
- parts far off-screen can have their contents ‘skipped’ — the
browser does simply sufficient to know the place the aspect sits, however doesn’t
lay out or paint the subtree, - whereas skipped, the weather successfully have structure, model, paint, and
dimension containment utilized, and - the
contain-intrinsic-sizeworth tells the browser what dimension to
assume for structure functions earlier than it has really rendered the
contents.
That is notably efficient for lengthy and repetitive pages or lists. You get
the efficiency advantages of virtualisation with out having to wire up a full
virtualised listing implementation, so long as you possibly can present an affordable dimension
estimate.
In actual fact, I take advantage of content-visibility on this web page you’re studying proper now:
.s-post > h2:nth-of-type(2) ~ p {
content-visibility: auto;
contain-intrinsic-size: 1px 250px;
}
This moderately unwieldy selector targets each paragraph after the second <h2> on
the web page, renders them lazily with content-visibility, and units their
placeholder dimension to at least one pixel huge and 250 pixels tall. These numbers are
considerably magic and the 250 is derived from ‘roughly how large the typical
paragraph on a web page is’ — nothing extra sophisticated than that.
Accessibility and Script Issues
As a result of the DOM nodes nonetheless exist, off-screen content material with
content-visibility: auto can often nonetheless be:
- surfaced to engines like google and different bots,
- discovered by way of in-page search,
- focused by way of anchor hyperlinks, and
- interacted with by way of assistive applied sciences.
Nonetheless:
content-visibility: hiddenis extra like a performance-friendly
visibility: hiddenplus containment. The content material shouldn’t be rendered and
could also be faraway from the accessibility tree, relying on the browser.- Any JavaScript that queries structure or model (
getBoundingClientRect,
getComputedStyle, and so on.) on a skipped subtree might power the browser
to render it early, consuming into your efficiency positive aspects. Protecting such
calls away from skipped content material is vital.
Your mileage might fluctuate.
Caveats, Gotchas, and Issues to Look ahead to
Containment shouldn’t be free. You’re buying and selling world flexibility for native
isolation, and that commerce can shock you in a number of methods.
Zero-Sized Containers
The most typical error with dimension containment (instantly or by way of
content-visibility) is forgetting to offer an specific or intrinsic
dimension. The browser then treats the aspect as if it had no kids when
computing its dimension, and in lots of layouts which means it collapses to
zero.
Signs embody:
- content material that seems ‘lacking’ however nonetheless exists within the DOM,
- scrollbars not behaving as anticipated,
- structure shifts as content material does get rendered, or
- click on targets which can be current however not seen.
The treatment is straightforward: at all times pair comprise: dimension or content-visibility: auto
with contain-intrinsic-size or applicable width/peak constraints.
Surprising Clipping
comprise: paint (instantly or by way of content material/strict) will clip portray to the
padding field. That’s typically precisely what you need, however it’ll break patterns
that depend on overflow:
- tooltips or dropdowns applied as kids,
box-shadow‘bleeds’ past the cardboard boundary, or- ornamental parts which can be positioned partially outdoors a piece.
In these circumstances, both transfer the overflowing aspect out of the contained subtree
or keep away from paint containment on that exact container.
Stacking Contexts In all places
Every structure or paint containment boundary establishes a stacking context
and a containing block. That is often a profit, however can add up:
z-indexdebugging turns into extra concerned as a result of extra parts outline their
personal stacking contexts,mounted-position kids might abruptly anchor to a widget as a substitute of the
viewport, and- combos with
rework/opacity-driven stacking contexts can grow to be
difficult.
In the event you ever end up pondering why is that this tooltip behind that
, verify for containment on ancestor parts as a part of your
overlay?
debugging guidelines.
Interplay with Container Queries
Container queries depend on sure types of containment underneath the hood; for
instance, container-type: inline-size successfully applies structure and elegance
containment to outline a question container.
Which means:
- If you’re already utilizing container queries, you might get a number of the
advantages of containment ‘free of charge’ on these containers. - In the event you add extra specific containment on the identical parts with out
eager about it, you would possibly over-constrain issues, notably with
dimensionorpaint.
A wise strategy is to deal with question containers as locations the place you
fastidiously overview which sorts of containment are already utilized earlier than
including extra.
When to Use Containment
By this level it’s best to have a good psychological map of what the completely different
containment values do. The remaining query is when to really apply
them.
Here’s a pragmatic guidelines.
Good Candidates
It is best to strongly contemplate comprise: content material (or related) for:
- self-contained playing cards or tiles organized in grids or lists;
- repeated article previews on index pages;
- sections of a protracted, scrolling web page which can be visually and functionally
unbiased; and - third-party widgets that ought to not bleed into the remainder of the structure.
It is best to contemplate content-visibility: auto plus
contain-intrinsic-size for:
- very lengthy lists of comparable gadgets the place many are off-screen;
- pages with dozens of article previews or product tiles; and
- heavy, principally static sections additional down a web page.
Use With Care
Be cautious with:
comprise: strict: use it solely when you’ve got explicitly sized
parts and no desired overflow.comprise: dimensionorinline-size: at all times present intrinsic or
specific sizes, and at all times take a look at in a variety of layouts.paintcontainment round elements that deliberately overflow
(tooltips, dropdowns, overlays).
Most likely Keep away from
Containment often does not belong on:
- root- or page-level wrappers the place every little thing inside is interdependent;
- small inline parts like buttons or labels; or
- parts whose complete goal is to increase past their very own bounds
visually.
Closing Ideas
CSS containment is a function that may yield huge profit when nicely deployed.
It lets the browser do much less work and offers you higher management over the place you
spend your purple time.
You don’t want to use it in every single place — and it would even be a micro optimisation
in your use-case — however a small handful of well-placed guidelines could make measurable
enhancements to the interactivity of your UI.
Begin small, measure
fastidiously, and maintain
an eye fixed on the gotchas, however earlier than you already know it, you’ll have a finely tuned
interface that leaves as small a footprint as attainable.
Hopefully that’s lifted containment from an obscurity to an on a regular basis a part of
your arsenal.
This Net Efficiency put up is tagged with:
Steadily Requested Questions
What’s CSS containment?
CSS containment is a strategy to isolate elements of the web page so the browser can restrict how far structure, paint, dimension, or model calculations must unfold.
What does the comprise property do?
The comprise property tells the browser which sorts of labor a part can maintain to itself, utilizing values similar to structure, paint, dimension, and elegance.
When ought to I take advantage of CSS containment?
It really works finest on self-contained UI islands similar to drawers, widgets, panels, or elements whose inside modifications shouldn’t have an effect on the remainder of the web page.
What’s the distinction between comprise and content-visibility?
comprise constrains browser work round a part, whereas content-visibility can go additional by skipping work for off-screen content material till it’s wanted.
Can CSS containment trigger bugs?
Sure. It could possibly introduce clipping, sizing surprises, new stacking contexts, and different uncomfortable side effects, so it needs to be utilized intentionally and examined fastidiously.

