Display locking is a set of API changes that make it straightforward for developers and browsers to easily scale to large amount of content and control when rendering  work happens. More concretely, the goals are:
Avoid loading  and rendering work for content not visible to the user.
Support user-agent features and all layout algorithms (e.g. responsive design, flexbox, grid) for this content
Support developer-controlled pre-loading, pre-rendering and measurement of content without having to fully render it to the screen
The following use-cases motivate this work:
- Fast display of large HTML documents (examples: HTML one-page spec, other long documents)
- Deep links and searchability into pages with hidden content (example: mobile Wikipedia)
- Scrollers with a large amount of content, without resorting to virtualization (examples: twitter feed, codemirror documents)
- Single-page app transitions. (Example: improving latency to show content not currently displayed but predicted to be soon, but without jank. Think search as you type, tabbed UIs, hero element clicks.)
- Layout measurement (examples: responsive design or animation setup)
Motivation & background
On the one hand, faster web page loads and interactions directly improve the user experience of the web. On the other hand, web sites each year grow larger and more complex than the last, in part because they support more and more use cases, and contain more information. This leads to pages with a lot of DOM, and since the DOM presently renders atomically, it inherently takes more and more time to render on the same machine.
For these reasons, web developers need ways to reduce loading and rendering time of web apps that have a lot of DOM. Two common techniques are to mark non-visible DOM as "invisible" , or to use virtualization . Browser implementors also want to reduce loading and rendering time of web apps. Common techniques to do so include adding caching of rendering state , and avoiding rendering work  for content that is not visible.
These techniques can work in many cases but have drawbacks and limitations:
a.  and  usually means that such content is not available to user-agent features, such as find-in-page functionality. Also, content that is merely placed offscreen may or may not have rendering cost (it depends on browser heuristics), which makes the technique unreliable.
b. Caching intermediate rendering state is hard work, and often has performance limitations and cliffs that are not obvious to developers. Similarly, relying on the browser to avoid rendering for content that is clipped out or not visible is sometimes not reliable, as it's hard for the browser to efficiently detect what content is actually visible.
Previously adopted web APIs, in particular the contain and will-change CSS properties, add ways to specify forms of rendering isolation or isolation hints, with the intention of them being a mechanism for the web developer to help the browser optimize rendering for the page.
While these forms of isolation help, they do not guarantee that isolated content does not need to be rendered at all. Ideally there would be a way for the developer to specify that specific parts of the DOM need not be rendered, and pair that with a guarantee that when later rendered, it would not invalidate more than a small amount of style, layout or paint in the rest of the document.
As the proposed features evolve, several competing API shapes might be considered at the same time, the decisions on particular behaviors might not be finalized, and some documentation may be out of date.
For the latest implemented behavior and API state, please consult the cheatsheet.
For behaviors being discussed, as well as questions and other discussions, please look over the issues
The rest of this document talks about one particular implementation option. Whether or not this is the final proposed set of features is yet undecided.
Three new features are proposed:
rendersubtreeattribute (early draft spec here). This controls whether DOM subtrees do or do not render, and is the mechanism by which rendering work can be avoided. User-agent features may modify this attribute, causing on-demand rendering, if desired. The developer may listen to this on-demand rendering via a MutationObserver and respond to it before rendering occurs.
rendersubtree, when present, forces
sizecontainment if invisible. This ensures minimal invalidation of the rest of the document when rendering occurs.
content-sizeattribute (early draft spec here that specifies how much space a subtree should take up. This is intended to allocate a placeholder size for content marked as invisible by
rendersubtree(since it already has
sizecontainment, as mentioned above). (Please note that this property in particular has been discussed and changed quite a bit; the latest discussion can be found here)
updateRenderingmethod on Element objects. This can be used to pre-render content within a subtree marked with
rendersubtreeas invisible to make it ready for display or measurement.
<div id=target rendersubtree="invisible skip-activation" style="content-size: 200px 200px">...content...</div> <script> target.setAttribute('rendersubtree', ''); // makes #target render </script>
This div's subtree is not rendered (but the div itself is; this allows the div to show fallback or "loading..." affordances), and there is no need for the browser to do any rendering lifecycle phases for the subtree of the div. The div lays out as if it had a single 200px by 200px child, which serves as a placeholder in order to take up the approximate layout size of the div's subtree. This allows page layout to be approximately correct, and preserves layout overflow size for scrolling. The browser may not render the content, even via a user-agent feature.
<div rendersubtree="invisible skip-viewport-activation" style="content-size: 200px 200px">...content</div>
Same as above, except that user-agent features may change the
attribute to the empty string, causing the div's subtree to get rendered. More
on this on "Element activation by the user agent"
(this is also covered in the cheatsheet).
<div id=target rendersubtree="invisible" style="content-size: 200px 200px">...content...</div> <script> target.setAttribute('rendersubtree', ''); // makes #target render </script>
Same as above, except that user-agent will also activate when content comes close to entering the visible viewport. Note that conceptually this is meant to make the element visible by the time it enters the viewport. Due to the fact that rendering work takes some time, the user-agent may make the element visible before it enters the viewport to allow more time for the rendering steps to take place.
<div id=target rendersubtree="invisible holdupgrades holdloads" style="content-size: 200px 200px">...content...</div>
Same as just having the
invisible value, but custom element upgrades are not
performed and resources are not loaded. Note that these values can also be used
invisible value also.
<div rendersubtree style="content-size: 200px 200px">...content</div>
This div and its subtree render, but still has
content-size has no effect because it doesn't have
size containment. This
rendersubtree is valuable beause when the div later becomes
invisible, invalidations of rendering state are minimized.
<div id=target rendersubtree="invisible skip-activation" style="content-size: 200px 200px">...content...</div> <script> target.updateRendering().then(() => console.log(target.firstElementChild.offsetTop)); // fast! </script>
The div's subtree does not render to the screen, but when updateRendering is
called, the browser does work in the background to prepare to render it quickly
in the future. This includes loading external resources referred to in the
subtree and custom element upgrades. It also may include running the rendering
lifecycle steps for the subtree up to and including style, layout, paint and
raster. When the returned promise resolves, reading layout or style-inducing
properties on the subtree is expected to be fast. Removing the
rendersubtree attribute is also expected to render the content
Element activation by the user agent
When an element is not rendered because it's a part of a not-rendered subtree
rendersubtree, there are some actions in the page that might require
the element (and its ancestors) to be rendered to work properly. If all of the
element's ancestors with
rendersubtree=invisible attribute allow activation
(as dictated by skip-activation and skip-viewport-activation tokens), then the
user agent can activate the element. This will change all of the non-null
rendersubtree value of all of its inclusive ancestors to the empty string -
causing the element and its ancestors to get rendered.
<div id="focusable" rendersubtree="invisible" tabindex=0>Focus me!</div> <script> focusable.focus(); // Will cause the element to render, and will change the rendersubtree value to "" (empty string) </script>
Note that if any of the element's ancestor is not activatable (the
rendersubtree is not null but, for example, also contains
then the element is not activatable.
Actions that will trigger activation to an element and all of its ancestors, are listed in the cheatsheet.
Activation fires a new
rendersubtreeactivation event when the element is
activated. The event fires at the beginning of the animation frame, prior to
display:none CSS property causes content subtrees not to render. However,
there is no mechanism for user-agent features to cause these subtrees to render.
visibility: hidden causes subtrees to not paint, but they still need style and
layout, as the subtree takes up layout space and descendants may be
visibility: visible. Second, there is no mechanism for user-agent features to cause
subtrees to render.
contain: strict allows the browser to automatically detect subtrees that are
definitely offscreen, and therefore that don't need to be rendered. However,
contain:strict is not flexible enough to allow for responsive design layouts
that grow elements to fit their content. (To work around this, content could be
contain:strict when offscreen and then some other value when
on-screen (this is similar to
contain:strict may or
may not result in rendering work, depending on whether the browser detects the
content is actually offscreen. Third, it does not support pre-rendering or
user-agent features in cases when it is not actually rendered to the user in the
current application view.
: Meaning, the rendering part of the browser event loop.
: Examples: fetching images off the network, custom element upgrade callbacks
: Examples: placing
display:none CSS on DOM subtrees, or by placing content
far offscreen via tricks like
: In this context, virtualization means representing content outside of the DOM, and inserting it into the DOM only when visible. This is most commonly used for virtual or infinite scrollers.
: Examples: caching the computed style of DOM elements, the output of text / block layout, and display list output of paint.
: Examples: detecting elements that are clipped out by ancestors, or not visible in the viewport, and avoiding some or most rendering lifecycle phases for such content.