Modern browsers are significantly more efficient in rendering complex HTML, CSS, and JavaScript code of web pages, converting code into available pages in just a few milliseconds.
So, how can front-end developers further improve browser rendering speed? In addition to those best practices that are easily forgotten (especially when we have limited control over the generated code), such as streamlining the CSS selector, keeping the HTML structure flat, and being careful to manipulate HTML and CSS in JavaScript, we can also take advantage of contain
properties of CSS.
contain
property allows developers to specify to what extent an element and its content is independent of the rest of the document tree. This enables the browser to recalculate layouts, styles, drawings, sizes, or any combination of them only for a limited area of the DOM (rather than the entire page), resulting in a significant performance improvement.
Simply put, contain
attribute can provide a prompt for the browser about the relationship between the elements on the page, which are usually container elements that contain content, even if the content is dynamic. For example, in single page applications (SPA), dynamic content is often inserted and deleted in the page, often independent of other content on the page.
The browser cannot predict future layout changes that may result from JavaScript insertion and deletion of page content. Even simple operations, such as adding class names to elements, animate DOM elements, or getting element sizes, can lead to page rearrangement and redrawing, which are expensive and should be avoided or reduced as much as possible.
Developers can predict possible future changes based on the user experience of the page design. For example, when a user clicks a button, the call data will be inserted into a div element in the current view. We know this is possible, but the browser doesn't. We also know that inserting data into the div element will most likely not change the visual effects or other aspects of other elements on the page.
Browser developers have spent a lot of time optimizing their browsers to handle this situation. While there are various ways to help the browser handle this situation more efficiently, more direct tips can be more helpful. contain
property provides us with a way to provide these hints.
Various usages of contain
attribute
contain
attribute has three values, which can be used alone or in combination: size
, layout
, and paint
. It also has two abbreviation values for common combinations: strict
and content
. Let's understand what each value means.
It should be noted that many rules and edge cases for each value are covered in the specification. In most cases, these rules may not attract much attention. However, if you get unexpected results, a quick look at the specification may be helpful.
There is also a style that contains types in the specification, which will not be introduced in this article. The reason is that the current style inclusion types are considered to be of little value and are currently at risk of being removed from the specification.
size
contains
size
contains is easy to explain. When the container containing this includes participates in layout calculations, the browser can skip a considerable portion of the calculations because it ignores the child elements of the container. The container is expected to have a set height and width; otherwise, it will collapse, and that is the only factor to consider in the page layout. It is considered as having nothing.
Note that child elements may affect the size of their container, depending on the style of the container. This must be considered when calculating the layout; using size
inclusion, it is likely not to be considered. Once the container has been determined relative to the page size, the layout of its child elements will be calculated.
size
inclusion itself does not provide much optimization. It is usually used in combination with other values.
However, one benefit it can provide is to help deal with JavaScript that changes container child elements based on container size, such as container query type. In some cases, changing the child element according to the size of the container may cause the container to change the size after making changes to the child element. Since the change in container size may trigger another change to the child element, you may end up with a change loop. size
contains can help prevent this loop.
Here is a completely artificial example about this resize loop concept: (A code example should be inserted here showing how size
contains how to prevent resize loops)
layout
contains
layout
contains a layout that tells the browser that external elements do not affect the internal layout of the container element, nor does it affect the internal layout of the container element affect the external elements. Therefore, when the browser does layout calculations, it can assume that having the various elements contained in layout
will not affect other elements. This can reduce the amount of computations that need to be performed.
Another benefit is that if the container is off-screen or blocked, the relevant calculations can delay or reduce priority. An example provided by the specification is:
[…] For example, if the include box is near the end of the block container and you are looking at the beginning of the block container
A container with layout
contains becomes a containing block of absolute or fixed position child elements. This is the same as applying the relative position to the container. So remember how to affect the child elements of the container when applying this type of inclusion.
Likewise, the container gets a new stacking context, so z-index
is used in the same way as the application is relative, absolute, or fixed. However, setting top
, right
, bottom
, or left
attributes has no effect on the container.
Here is a simple example: (A code example should be inserted here showing how layout
contains affects layout and stacking context)
paint
contains
paint
contains telling the browser that the child elements of the container will never be drawn outside the boundary of the container box size. This is similar to setting overflow: hidden;
on a container, but with some differences.
First, the container is handled the same way as it is under layout
inclusion: it becomes a containing block with its own stacking context. Therefore, the child elements positioned in paint
include will respect the container in terms of position. If we want to copy the above layout
include demo but use paint
include instead, the result will be roughly the same. The difference is that when the application contains, the purple line does not overflow the container, but is clipped at the border of the container.
Another interesting benefit of paint
includes is that if the browser can detect that the container itself is not visible in the viewport, it can skip the drawing calculation of the child elements of that element. If the container is not in the viewport or is obstructed in some way, then its children are guaranteed to be invisible. For example, consider a navigation menu that is usually located off the screen on the left side of the page, which slides in when the button is clicked. When the menu is in its normal off-screen state, the browser simply skips trying to draw its contents.
Various combinations of included
These three include different methods that affect the rendering calculations performed by the browser. size
contains telling the browser that this container should not cause position offset on the page when its content changes. layout
contains telling the browser that child elements of this container should not cause layout changes in elements outside of its container, and vice versa. paint
contains telling the browser that the contents of this container will never be drawn outside the container size and that if the container is blocked, the contents will not be drawn at all.
Since each include provides different optimizations, it makes sense to combine some of the include together. The specification actually allows this. For example, we can use layout
and paint
as the value of contain
property as follows:
.el { contains: layout paint; }
Since this is a very obvious thing, the specification actually provides two abbreviation values:
content
value will be the most commonly used value in a web project, containing many dynamic elements, such as large multiple containers that change content over time or user activity.
strict
value is useful for containers with defined sizes that never change sizes (even if the content changes). Once in place, it will maintain the expected size. A simple example is a div containing third-party external advertising content, whose dimensions are defined by the industry and have nothing to do with any other DOM elements on the page.
Performance Advantages
This part of the article is difficult to explain. The problem is that there are not many visual effects on performance advantages. Most of the benefits are behind-the-scenes optimizations, helping the browser decide what to do when layout or drawing changes.
To show the performance advantages of the contain
attribute, I made a simple example, which changed the font size of an element with multiple child elements. This change usually triggers a relay, which also causes the page to be redrawn. This example covers contain
values of none
, content
and strict
. (Code examples and performance test results should be inserted here)
Layout once, draw twice
Please listen to my explanation patiently. I promise it will make sense.
I'll use the above demonstration as the basis for the following description. If you wish to continue learning, visit the full version of the demo and open DevTools. Note that after running the performance tool, you have to turn on the details of the "frame" instead of the "main" timeline to see what I'm about to describe.
I'm actually taking screenshots from the "fullpage" version, because DevTools works better in that version. That said, the regular version of "full" should provide roughly the same idea.
In the event log of the task that is not included, the drawing event is triggered only once. Typically, events do not take too long, ranging from 0.2 milliseconds to 3.6 milliseconds. The deeper details are where it becomes interesting. In these details, it states that the drawing area is the entire page. In the event log, DevTools even highlights the drawn page area if you hover over the draw event. In this case, the size will be the size of the browser viewport. It will also notice the layer root drawn.
Note that the page area to the left of the image is highlighted, even outside the purple box. On the right side, is the size drawn to the screen. In this case, it is approximately the size of the viewport. For future comparisons, please note #document as the layer root.
Remember that the browser has layer concepts for certain elements to help draw. Layers are often used for elements that may overlap with each other due to the new stacking context. An example is applying position: relative;
and z-index: 1;
to an element will cause the browser to create the element as a new layer. contain
property has the same effect.
There is a section in DevTools called "rendering" which provides various tools to see how the browser renders the page. When selecting a checkbox called "Layer borders", we can see different contents depending on the inclusion. When included is none
, you should not see layers beyond the typical static web page layer. Select content
or strict
and you can see that the purple box converts to its own layer and the rest of the page changes accordingly. (Screenshots should be inserted here to show layers under different inclusion types)
As I mentioned before, both content
and strict
cause the draw event to be fired twice. This is because two different drawing processes are performed for two different reasons. In my demo, the first event is for the purple box and the second event is for the contents of the purple box.
Typically, the first event will draw a purple box and report the dimensions of that box as part of the event. The box is now its own layer and enjoys the benefits it applies.
The second event is used for the content of the box because they are scrolling elements. As the specification explains; because the stacking context is guaranteed, the scrolling element can be drawn into a single GPU layer. The higher size reported in the second event is the height of the scroll element. Probably even narrower to make room for scroll bars.
Note the difference in the dimensions to the right of these two images. Additionally, the layer roots of both events are main.change instead of the #document seen above. The purple box is a main element, so only that element is drawn instead of the entire document. You can see the highlighted box instead of the entire page.
The advantage of this is that when scrolling elements are usually made to be drawn when they enter the field of view. The scroll elements in the containment have been drawn, so they are not necessary to be drawn again when entering the field of view. So we also get some rolling optimizations.
Again, this can be seen in the demo. (Screenshots should be inserted here to show the scrolling performance under different inclusion types)
An interesting accidental discovery
I had an interesting problem when I tried the demo above and understood how the drawing and scrolling performance aspects work. In one test, I have a simple box in the center of the page, but with minimal style. It is essentially a scrolling element with a lot of text content. I applied the contents to the container elements, but I didn't see the scrolling performance advantages described above.
The container is marked with a "repaints on scroll" overlay and the drawing flicker is the same as if the included is not applied, even if I know that the content contains is actually applied to the container. So I started comparing my simple tests to the more styling-rich version discussed above.
I ended up finding that if background-color
of the container is transparent, there is no inclusion scrolling performance advantage.
I ran a similar performance test where I will change the font size of the content to trigger relayout and redraw. The results of the two tests are roughly the same, the only difference is that background-color
of the first test is transparent and background-color
of the second test is the appropriate color. From the numbers, behind-the-scenes calculations are still more efficient; only the plotting events are different. It seems that elements do not become their own layer in the drawing calculation with transparent background-color
.
The first test run has only one draw event in the event log. The second test run has two plot events, as I expected. Without that background color, the browser seems to decide to skip the included layer aspects. I even found that forging transparency by using the same color as the one behind the element also works fine. My guess is that if the background of the container is transparent, then it must depend on anything below, which makes it impossible to separate the container into its own drawing layer. (Screenshots should be inserted here to show different results under transparent background colors and opaque background colors)
I made another version of the test demo that changed background-color
of the container element from transparent to the same color as the body background color. Here are two screenshots of using the various options in the "Rendering" panel in DevTools. (Screenshots should be inserted here to show different results under transparent background colors and opaque background colors)
Summarize
This article introduces the basics of CSS contain
properties, including their values, benefits, and potential performance improvements. There are some benefits to applying this attribute to certain elements in HTML; which elements need to apply this attribute is up to you. At least, that's what I understand, because I don't know any specific guidance. The general idea is to apply it to containers of other elements, especially those with some dynamic aspect.
Some possible scenarios: grid areas of the CSS grid, elements containing third-party content, and containers with dynamic content based on user interaction. There should be no harm in using this property in these cases, assuming you are not trying to include an element that actually depends on another element outside of that include.
Browser support is very powerful. Safari is the only browser that is not supported at present. Anyway, you can still use the property because if the browser doesn't understand the property or its value, it simply skips the code without error.
So feel free to start including your content!
The above is the detailed content of Let's Take a Deep Dive Into the CSS Contain Property. For more information, please follow other related articles on the PHP Chinese website!

Custom cursors with CSS are great, but we can take things to the next level with JavaScript. Using JavaScript, we can transition between cursor states, place dynamic text within the cursor, apply complex animations, and apply filters.

Interactive CSS animations with elements ricocheting off each other seem more plausible in 2025. While it’s unnecessary to implement Pong in CSS, the increasing flexibility and power of CSS reinforce Lee's suspicion that one day it will be a

Tips and tricks on utilizing the CSS backdrop-filter property to style user interfaces. You’ll learn how to layer backdrop filters among multiple elements, and integrate them with other CSS graphical effects to create elaborate designs.

Well, it turns out that SVG's built-in animation features were never deprecated as planned. Sure, CSS and JavaScript are more than capable of carrying the load, but it's good to know that SMIL is not dead in the water as previously

Yay, let's jump for text-wrap: pretty landing in Safari Technology Preview! But beware that it's different from how it works in Chromium browsers.

This CSS-Tricks update highlights significant progress in the Almanac, recent podcast appearances, a new CSS counters guide, and the addition of several new authors contributing valuable content.

Most of the time, people showcase Tailwind's @apply feature with one of Tailwind's single-property utilities (which changes a single CSS declaration). When showcased this way, @apply doesn't sound promising at all. So obvio

Deploying like an idiot comes down to a mismatch between the tools you use to deploy and the reward in complexity reduced versus complexity added.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Chinese version
Chinese version, very easy to use

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.