Wednesday, September 30, 2026
HomeCSSWhat Is CSS Containment and How Can I Use It? – CSS...

What Is CSS Containment and How Can I Use It? – CSS Wizardry


in

Net Efficiency

• 13 minute learn

Written by on CSS Wizardry.

View this web page as Markdown.

Desk of Contents

Unbiased writing is dropped at you by way of my fantastic
Supporters.

  1. Why Containment Exists
  2. Meet the comprise Property
  3. Format Containment
  4. Paint Containment
  5. Measurement Containment
  6. Model Containment
  7. Particular Values: content material and strict
    1. comprise: content material
    2. comprise: strict
  8. Containment within the Actual World
    1. OpenTable’s Cell Drawer
    2. Different Good Candidates
  9. content-visibility and contain-intrinsic-size
    1. Skipping Work with content-visibility
    2. Accessibility and Script Issues
  10. Caveats, Gotchas, and Issues to Look ahead to
    1. Zero-Sized Containers
    2. Surprising Clipping
    3. Stacking Contexts In all places
    4. Interplay with Container Queries
  11. When to Use Containment
    1. Good Candidates
    2. Use With Care
    3. Most likely Keep away from
  12. 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
deal with it as a self-contained island
. In return, the browser is free to skip
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!

Want Some Assist?

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:

  1. recalculate types for affected parts,
  2. recalculate structure (sizes and positions),
  3. repaint the pixels that modified, and
  4. 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 for structure paint model.
  • strict: shorthand for dimension 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 .card don’t have an effect on structure
    outdoors of .card,
  • the .card establishes its personal formatting context (like a mini structure world),
  • floats and margin-collapsing are contained inside .card,
  • .card turns into the containing block for place: absolute and
    place: mounted descendants, and
  • a brand new stacking context is created, so z-index on kids is scoped
    to that card.

This has two foremost penalties:

  1. 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.
  2. Format behaviour. The brand new formatting context and containing block could be
    very helpful for controlling floats, margin-collapsing, and place: 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: mounted for 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 .card can visibly overflow its padding field,
  • if the .card itself 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 use comprise: paint on that aspect.
  • In the event you mix structure and paint containment, 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 .widget is 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 .part won’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: mounted kids 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.

Want Some Assist?

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%:

11.21ms of structure work, rooted at #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:

Chrome DevTools performance profile showing OpenTable’s mobile drawer after applying contain: strict. The layout root is now the drawer itself, touching 73 nodes and laying out 40 of them in 1.89 milliseconds.
1.89ms of structure work, rooted on the drawer itself, touching 73 nodes to relayout 40. View full dimension/high quality (1MB)

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-size worth 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: hidden is extra like a performance-friendly
    visibility: hidden plus 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-index debugging 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
overlay?
, verify for containment on ancestor parts as a part of your
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
    dimension or paint.

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: dimension or inline-size: at all times present intrinsic or
    specific sizes, and at all times take a look at in a variety of layouts.
  • paint containment 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.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments