diff --git a/document-render-blocking.md b/document-render-blocking.md index c0e720d..44aa85b 100644 --- a/document-render-blocking.md +++ b/document-render-blocking.md @@ -3,6 +3,12 @@ The Web is designed with a model for incremental rendering. When a Document is loading, the browser can render its intermediate states before fetching all the requisite sub-resources, executing all script or fetching/parsing the complete Document. While this is great to reduce the time for first paint, there is a tradeoff between showing a jarring flash of intermediate Document state (which could be unstyled or have more CLS) vs blocking rendering on high priority sub-resources within a reasonable timeout. The [render-blocking](https://html.spec.whatwg.org/#render-blocking-mechanism) concept helps browsers in making this tradeoff. It lets authors specify the set of stylesheets and script elements which should block rendering. For example, a stylesheet with the rules necessary to ensure a stable layout. But authors can’t specify which nodes should be added to the DOM before first render. This proposal aims to fill this gap. + +### Disclaimer + +Incremental rendering is a fundamental aspect of the Web. It ensures users wait the minimal time necessary before seeing any content from the new Document. At the same time, the tradeoff between a "good" (stable layout with above the fold content) and "fast" (how soon the first frame shows up) is difficult to get right. For this reason, browsers err towards keeping this tradeoff internal to prevent developers from unintentionally regressing the user experience. + +While we acknowledge that the View Transition use-case necessitates author input into this tradeoff, we want to strive for an API shape which keeps the feature from becoming a footgun for authors. # View Transitions Use Case @@ -20,14 +26,47 @@ The main use-case for this proposal is [cross-document View Transitions](https:/ Identifying all animations correctly requires the browser to render-block the new Document until all elements which will be assigned a view-transition-name have been added to the DOM. Otherwise morph animations will turn into exit animations and entry animations will get skipped. Since browsers use heuristics to optimally yield and render when fetching a new Document, a consistent transition UX across all browsers is not feasible without an explicit hint from developers to delay rendering until the requisite nodes have been parsed. -# Proposal +# Other Use Cases + +There are a few other scenarios where a feature to control when the parser yields for rendering can be helpful: + +- Lower CLS: A stable layout of the DOM depends on both parsing the requisite DOM nodes and fetching relevant stylesheets. Without control over parsing, its possible that the browser does multiple renders with layout shifts as more of the DOM is parsed. +Authors will sometimes initially set `display: none` or `opacity: 0` to hide the whole Document to prevent this, only showing it when enough of the Document is parsed. + +- Atomic rendering of semantic elements: A UI widget built using a DOM sub-tree might not make sense to render partially. Consider a menu where only half the buttons show up on first render. Authors could mark sections in the Document which semantically render one widget so the browser doesn't yield midway through parsing one widget. + +- Optimal Yielding: The browser may yield later than was necessary leading to rendering more what's required for above the fold content. A developer hint about a yielding trigger could imply the first frame has less DOM to parse, style, and layout. Browsers can optimize paint to be limited to onscreen content but the prior stages are executed over the entire DOM. +However, its difficult for authors to know when the above-the-fold content ends given the variety of device form factors. This situation could also be solved better by `content-visibility: auto` which can optimize out style/layout for offscreen content. + +These use-cases are not the primary problem targeted by this proposal, they are listed to evaluate whether the ability to block parsing should be limited to when the new Document will be displayed with a View Transition or all loads. + +# Dependencies + +The set of elements which need to block rendering for View Transition depends on which Document the user is coming from. A real world example is as follows. + +The user is navigating between Documents of a site which has a header. This header can be scrolled offscreen by the user, so it's not guaranteed to be onscreen when a navigation is initiated. The following cases are possible: + +- The header was onscreen on the old Document and will be onscreen on the new Document. The author wants a morph animation which needs the header to be parsed before first render. + +- The header was not onscreen on the old Document and/or won't be onscreen on the new Document (for instance because of scroll restoration). The author wants just a full page animation, header does not need to be parsed before first render. + +The above requires the new Document to know about the old Document's visual state when the transition started. This can't be done trivially today. The Navigation API provides the list of [entries](https://developer.mozilla.org/en-US/docs/Web/API/Navigation/entries) and the [current entry](https://developer.mozilla.org/en-US/docs/Web/API/Navigation/currentEntry) but there is no notion of a "previous entry" before the current entry was committed. + +[html/256](https://github.com/WICG/navigation-api/issues/256) addresses this. The examples in this proposal rely on the API proposed. + +# Proposals + +## Blocking Attribute Add the [blocking attribute](https://html.spec.whatwg.org/#blocking-attributes) on the [HTMLHtmlElement](https://html.spec.whatwg.org/multipage/semantics.html#the-html-element). This is the [document element](https://dom.spec.whatwg.org/#document-element) for an HTML Document. The timing for when this attribute can block rendering for a Document is already well defined in [render-blocking mechanism](https://html.spec.whatwg.org/multipage/dom.html#render-blocking-mechanism). The user agent [unblocks rendering](https://html.spec.whatwg.org/multipage/dom.html#unblock-rendering) on this element when it's done parsing the document as defined [here](https://html.spec.whatwg.org/multipage/parsing.html#the-end). -## Sample Code -### Block Rendering on Full Document Parsing +This approach neatly fits with the existing `blocking` primitive in html. The con is that while its trivial to block rendering until the full Document is parsed, more not-so-obvious code is needed to optimally block only on the minimal requisite set of elements. That makes it likely that authors will just block on full parsing since that will be an easier fix to the correctness issue. This will degrade the overall user experience by delaying the first frame longer than necessary. + +### Sample Code + +#### Block Rendering on Full Document Parsing ```html
@@ -36,16 +75,115 @@ The timing for when this attribute can block rendering for a Document is already ``` -### Block Rendering on Partial Document Parsing +#### Block Rendering on Partial Document Parsing + ```html + … +