Intent to Implement: Block parser on external CSS

1,204 views
Skip to first unread message

Patrick Meenan

unread,
Feb 1, 2016, 10:27:26 AM2/1/16
to blink-dev
Contact email:

Spec
N/A.  The internal parser behavior is not spec'd.

Summary
This is an internal change that doesn't change the API surface of the web but it does alter existing behavior (hopefully making it easier to reason about).

Currently, link tags referencing external stylesheets are loaded asynchronously and if their media type matches the current document it is flagged as a pending stylesheet and future paints are blocked until it is loaded.  Building of the DOM continues until the parser encounters a script tag where it will wait for any pending stylesheets to finish loading before continuing execution.

If an external stylesheet is referenced in the body it will block the painting of all of the content that was already parsed if a layout and paint didn't happen to occur before the parser reached the link tag.

A fairly common performance recommendation is to inline any styles for above-the-fold content and load the full styles from the body after the above-the-fold content has been defined so the initial viewport can (largely) be drawn from just the initial HTML response.  The current behavior makes that a racy proposition in Chrome and largely doesn't work.

My plan is to block the parser when it reaches a matching external stylesheet and eliminate all of the logic that tracks pending stylesheets and paint supression.  That way content defined before the stylesheet can continue to layout/paint/load while anything defined after the stylesheet will be held back until after it has loaded.

In addition to making it easier for web developers to reason about, it will also significantly simplify the logic within Chrome.

Is this feature supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?
Yes

Demo link

Interoperability and Compatibility Risk
Browser behavior in this area is quite varied.  The change will bring Chrome in line with how IE and Edge behave.

Chrome (currently): Blocks drawing of all content before and after the external css as soon as it is parsed
Safari: Same as Chrome (behavior inherited from WebKit)
Firefox: External stylesheets in the body do not block drawing of any content, including content referenced after the stylesheet (treated completely async)
Edge: Content before external stylesheets is drawn independently of the sheet loading and content referenced after it is blocked until after the sheet is loaded (same as proposed behavior)
IE 11: Same as Edge

The biggest risk is the potential for reduced performance by not continuing to parse the DOM while the stylesheet loads asynchronously.  Before the preload scanner this would have been a much more significant issue as external resources would not be discovered but that is no longer the case.  The parser would block as soon as it hit the next script tag anyway so the only loss is for the time to actually build the DOM nodes between the link tag and when the parser would have been blocked anyway.

OWP launch tracking bug
No launch bug created yet.  Current bug that led us down this path: https://crbug.com/481122

Entry on the feature dashboard
No entry created (though happy to create one if it is deemed necessary).

Boris Zbarsky

unread,
Feb 1, 2016, 10:38:02 AM2/1/16
to Patrick Meenan, blink-dev
On 2/1/16 10:27 AM, Patrick Meenan wrote:
> My plan is to block the parser when it reaches a matching external
> stylesheet

Just out of curiosity, are you talking about just stylesheets inside
<body> or also ones inside <head>?

> *Firefox*: External stylesheets in the body do not block drawing of any
> content, including content referenced after the stylesheet (treated
> completely async)

More precisely, the Firefox behavior is as follows:

1) External stylesheets in <head> don't prevent parsing, but they do
prevent layout and drawing, unless the page makes an explicit layout
information request. External stylesheets in <body> do not prevent
layout or drawing.

2) External sheets in both <head> and <body> block execution of later
<script> tags (to prevent those scripts getting incorrect layout
values), which can itself block parsing.

-Boris

Jake Archibald

unread,
Feb 1, 2016, 10:41:31 AM2/1/16
to Patrick Meenan, blink-dev
This is something developers have asked for (https://www.w3.org/Bugs/Public/show_bug.cgi?id=27303#c37).

This allows developers to include CSS just before the first use of a page component (eg, header, article, comment), giving a progressive render, and resulting in smaller cacheable chunks of CSS that are relevant to the page.

--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Patrick Meenan

unread,
Feb 1, 2016, 10:42:21 AM2/1/16
to Boris Zbarsky, Patrick Meenan, blink-dev
The current plan is to block the parser on all external styles (head and body).  That will let us eliminate all of the reference counting and tracking that has to happen before unblocking the initial painting and make it a simple case of "reached body tag, unblock commits".

That said, if there is push-back on blocking the parser on head styles I could implement it just for styles in the body.  It would keep all the benefits for web-devs to reason about but we'd lose some of the internal clean-up benefits.

Simon Pieters

unread,
Feb 1, 2016, 8:50:33 PM2/1/16
to blink-dev, Patrick Meenan
On Tue, 02 Feb 2016 02:27:20 +1100, Patrick Meenan <pme...@chromium.org>
wrote:

> *Contact email*:
> pme...@chromium.org
>
> *Spec*
> N/A. The internal parser behavior is not spec'd.

The current behavior is actually specified in HTML.

https://html.spec.whatwg.org/multipage/semantics.html#a-style-sheet-that-is-blocking-scripts


> *Summary*
I think this is a radical proposal and it would be interesting to evaluate
the pros and cons and compare with other approaches. Simplifying the
architecture seems like a clear pro.

As for cons, I can think of:

* Doing this would be a step back in terms of interop, I believe. The
logic to keep track of pending stylesheets and block inline scripts when
there are pending stylesheets is specified in the HTML spec and is, I
think, implemented in all engines (probably not perfect interop, but
still).

* Blocking parsing could regress performance in various cases, for
instance if a page has first an async script, then an external stylesheet,
and then a <video preload>; the video would not start to load until the
stylesheet is loaded. It would be possible to add <video> knowledge to the
speculative scanner, but that adds complexity to the speculative scanner
(and hence new bugs), and I assume <video> is not the only thing that
could regress.

* Blocking parsing might not be Web compatible. Given setTimeout(),
mutation observers, etc, it is possible to tell the difference between
blocking parsing and not blocking parsing. In particular there can be
pages that do setTimeout() and make assumptions about what is available in
the "future" DOM when it runs.


> *Is this feature supported on all six Blink platforms (Windows, Mac,
> Linux,
> Chrome OS, Android, and Android WebView)?*
> Yes
>
> *Demo link*
> http://test.patrickmeenan.com/css/image.html
>
> *Interoperability and Compatibility Risk*
> Browser behavior in this area is quite varied. The change will bring
> Chrome in line with how IE and Edge behave.
>
> *Chrome (currently)*: Blocks drawing of all content before and after the
> external css as soon as it is parsed
> *Safari*: Same as Chrome (behavior inherited from WebKit)
> *Firefox*: External stylesheets in the body do not block drawing of any
> content, including content referenced after the stylesheet (treated
> completely async)
> *Edge*: Content before external stylesheets is drawn independently of the
> sheet loading and content referenced after it is blocked until after the
> sheet is loaded (same as proposed behavior)
> *IE 11*: Same as Edge

I haven't tested Edge right now, but I very much doubt that it actually
blocks parsing for external stylesheets. I had assumed that it only blocks
layout of the post-external-stylesheet part of the DOM until the
stylesheet is loaded.

What I would suggest is to investigate more closely what Edge does here,
and consider blocking layout instead of blocking parsing, before going
ahead with implementation of blocking parsing. Also I would suggest that
if we do decide that blocking parsing is the better solution, that we have
other vendors on board with doing the same so that we don't end up with
worse interop, and so that we can change the HTML spec to match.

> The biggest risk is the potential for reduced performance by not
> continuing
> to parse the DOM while the stylesheet loads asynchronously. Before the
> preload scanner this would have been a much more significant issue as
> external resources would not be discovered but that is no longer the
> case.
> The parser would block as soon as it hit the next script tag anyway so
> the
> only loss is for the time to actually build the DOM nodes between the
> link
> tag and when the parser would have been blocked anyway.
>
> *OWP launch tracking bug*
> No launch bug created yet. Current bug that led us down this path:
> https://crbug.com/481122
>
> *Entry on the feature dashboard*
> No entry created (though happy to create one if it is deemed necessary).
>


--
Simon Pieters
Opera Software

Elliott Sprehn

unread,
Feb 1, 2016, 10:37:15 PM2/1/16
to Simon Pieters, blink-dev, Patrick Meenan
On Tue, Feb 2, 2016 at 12:50 PM, Simon Pieters <sim...@opera.com> wrote:
On Tue, 02 Feb 2016 02:27:20 +1100, Patrick Meenan <pme...@chromium.org> wrote:

*Contact email*:
pme...@chromium.org

*Spec*
N/A.  The internal parser behavior is not spec'd.

The current behavior is actually specified in HTML.

https://html.spec.whatwg.org/multipage/semantics.html#a-style-sheet-that-is-blocking-scripts


*Summary*

This is an internal change that doesn't change the API surface of the web
but it does alter existing behavior (hopefully making it easier to reason
about).

[...]

I think this is a radical proposal and it would be interesting to evaluate the pros and cons and compare with other approaches. Simplifying the architecture seems like a clear pro.

Only as radical as the Edge team! :D


As for cons, I can think of:

* Doing this would be a step back in terms of interop, I believe. The logic to keep track of pending stylesheets and block inline scripts when there are pending stylesheets is specified in the HTML spec and is, I think, implemented in all engines (probably not perfect interop, but still).

Blocking the parser on parser inserted scripts when there's parser inserted pending stylesheets is specified, what's not specified is when the parser yields and what is allowed to paint when a sheet is still downloading. WebKit, Blink, Firefox and Edge all do different things there.
 

* Blocking parsing could regress performance in various cases, for instance if a page has first an async script, then an external stylesheet, and then a <video preload>; the video would not start to load until the stylesheet is loaded. It would be possible to add <video> knowledge to the speculative scanner, but that adds complexity to the speculative scanner (and hence new bugs), and I assume <video> is not the only thing that could regress.

In general the preload scanner needs to learn all these things, it's a huge win when the connection setup cost is high. :)
 

* Blocking parsing might not be Web compatible. Given setTimeout(), mutation observers, etc, it is possible to tell the difference between blocking parsing and not blocking parsing. In particular there can be pages that do setTimeout() and make assumptions about what is available in the "future" DOM when it runs.


Maybe, but that code is already broken because it's racing the network and the parser yielding which can happen randomly, for example the scheduler will yield the parser whenever your finger touches the screen, Also note that IE/Edge block parsing and have for years.


*Is this feature supported on all six Blink platforms (Windows, Mac, Linux,
Chrome OS, Android, and Android WebView)?*
Yes

*Demo link*
http://test.patrickmeenan.com/css/image.html

*Interoperability and Compatibility Risk*
Browser behavior in this area is quite varied.  The change will bring
Chrome in line with how IE and Edge behave.

*Chrome (currently)*: Blocks drawing of all content before and after the
external css as soon as it is parsed
*Safari*: Same as Chrome (behavior inherited from WebKit)
*Firefox*: External stylesheets in the body do not block drawing of any
content, including content referenced after the stylesheet (treated
completely async)
*Edge*: Content before external stylesheets is drawn independently of the
sheet loading and content referenced after it is blocked until after the
sheet is loaded (same as proposed behavior)
*IE 11*: Same as Edge

I haven't tested Edge right now, but I very much doubt that it actually blocks parsing for external stylesheets. I had assumed that it only blocks layout of the post-external-stylesheet part of the DOM until the stylesheet is loaded.

It does actually block the parser, if you poll in setTimeout you'll see that while the sheet is still downloading the rest of the document doesn't get appended.

See the discussion of engine behavior in: https://code.google.com/p/chromium/issues/detail?id=481122#c38


What I would suggest is to investigate more closely what Edge does here,

We did, that's what informed our decision. :)
 
and consider blocking layout instead of blocking parsing,

This is what we try do today, and it's buggy and complicated for authors. Blocking layout for only part of the page is very complicated as well, so there's no easy way to say "only stuff after X should skip style/layout."

- E 

Dimitri Glazkov

unread,
Feb 1, 2016, 11:40:05 PM2/1/16
to Elliott Sprehn, Simon Pieters, blink-dev, Patrick Meenan
I think we should give it a shot. With my developer hat on, I can definitely see this being more intuitive. Fewer gotchas seems like a better thing.

:DG<

Simon Pieters

unread,
Feb 1, 2016, 11:42:26 PM2/1/16
to Elliott Sprehn, blink-dev, Patrick Meenan
On Tue, 02 Feb 2016 14:36:28 +1100, Elliott Sprehn <esp...@chromium.org>
wrote:

> Only as radical as the Edge team! :D

:-)

> Blocking the parser on parser inserted scripts when there's parser
> inserted
> pending stylesheets is specified, what's not specified is when the parser
> yields and what is allowed to paint when a sheet is still downloading.
> WebKit, Blink, Firefox and Edge all do different things there.

Right, indeed.


> In general the preload scanner needs to learn all these things, it's a
> huge
> win when the connection setup cost is high. :)

OK. In this world I think Gecko's speculative design where it actually
builds a DOM speculatively, would be more relevant to have. Correctly
handling things <script>, <svg>, and so on, speculatively is going to be
increasingly complex otherwise if the goal is to be able to speculatively
load <video>, SVG <image>, etc. But certainly that doesn't need to block
this work.


> Maybe, but that code is already broken because it's racing the network
> and
> the parser yielding which can happen randomly, for example the scheduler
> will yield the parser whenever your finger touches the screen,

Sure. I mentioned this because I recall some bug we had on Presto about
this. Hopefully it's small enough an issue that we can break through and
just say "well don't do that".


> Also note
> that IE/Edge block parsing and have for years.

OK, so I didn't know that and somehow was under the impression that it
blocked just the layout.


> It does actually block the parser, if you poll in setTimeout you'll see
> that while the sheet is still downloading the rest of the document
> doesn't
> get appended.

Very well then! :-)


> See the discussion of engine behavior in:
> https://code.google.com/p/chromium/issues/detail?id=481122#c38

Thx.


>> What I would suggest is to investigate more closely what Edge does here,
>
>
> We did, that's what informed our decision. :)
>
>
>> and consider blocking layout instead of blocking parsing,
>
>
> This is what we try do today, and it's buggy and complicated for authors.
> Blocking layout for only part of the page is very complicated as well, so
> there's no easy way to say "only stuff after X should skip style/layout."

Yeah, I meant doing partial layout and block layouting the post-<link>
DOM. I understand that it's not easy to do, and clearly nobody has done it
yet.

So what remains from my original message is to keep WebKit and Gecko
people in the loop, and we'll need to fix the HTML spec, and watch out for
compat and perf regressions...

Boris Zbarsky

unread,
Feb 2, 2016, 12:34:19 AM2/2/16
to blink-dev
On 2/1/16 11:42 PM, Simon Pieters wrote:
> So what remains from my original message is to keep WebKit and Gecko
> people in the loop, and we'll need to fix the HTML spec, and watch out
> for compat and perf regressions...

I'm not sure Gecko is interested at the moment in making a change like
this that seems to have minimal benefit, significant regression risk,
involves a fair amount of work, and goes from three of four engines
matching the spec to a 2-2 behavior split...

-Boris

Boris Zbarsky

unread,
Feb 2, 2016, 8:13:51 AM2/2/16
to blink-dev
On 2/2/16 12:34 AM, Boris Zbarsky wrote:
> I'm not sure Gecko is interested at the moment in making a change like
> this that seems to have minimal benefit, significant regression risk,

Notably, the main performance risk from my point of view is that unless
there's a <script> after the <link> you end up delaying DOMContentLoaded
and any loads that the page kicks off there (e.g. via jQuery's
$(document).ready() and whatnot).

-Boris

Elliott Sprehn

unread,
Feb 2, 2016, 8:17:54 AM2/2/16
to Boris Zbarsky, blink-dev
Indeed, I don't think we want to block the parser when inside the <head>, or more generally when we're deferring commits there's no reason to block the parser. Once we undefer we should block though, which essentially means sheets in the <body>.

- E 

Boris Zbarsky

unread,
Feb 2, 2016, 8:22:47 AM2/2/16
to Elliott Sprehn, blink-dev
On 2/2/16 8:17 AM, Elliott Sprehn wrote:
> Indeed, I don't think we want to block the parser when inside the
> <head>, or more generally when we're deferring commits there's no reason
> to block the parser. Once we undefer we should block though, which
> essentially means sheets in the <body>.

Note that deferring commits is not a concept the spec has.

In terms of a spec proposal, note that you also need to define what
happens in the XML serialization of HTML, or with <link> in SVG
documents. So cases when the <link> comes before <head>, between <head>
and <body>, after <body>, or when there are no <head> or <body> around
at all. Obviously this doesn't matter too much for actual behavior on
the web, but it might well matter in terms of implementation complexity.

-Boris

Elliott Sprehn

unread,
Feb 2, 2016, 8:33:50 AM2/2/16
to Boris Zbarsky, blink-dev
That's why I was suggesting keying this off deferred commit mode, that system handles all those cases today. :)

We probably should spec deferred commit behavior someday, Chrome doesn't run requestAnimationFrame until we un-defer (which is when we start painting), as running it while sheets are loading and we're not painting doesn't make sense.

- E 

Boris Zbarsky

unread,
Feb 2, 2016, 11:05:11 AM2/2/16
to Elliott Sprehn, blink-dev
On 2/2/16 8:33 AM, Elliott Sprehn wrote:
> That's why I was suggesting keying this off deferred commit mode, that
> system handles all those cases today. :)

Yes, I understand that; my point was that you can't spec something in
terms of a thing which isn't specified and claim you have a spec.

> We probably should spec deferred commit behavior someday

We should, but I expect it to be rather contentious: different browsers
have different heuristics and different architectures around this stuff,
and we may want to allow some room for experimentation on those
heuristics...

-Boris

Jake Archibald

unread,
Feb 12, 2016, 7:12:41 AM2/12/16
to Patrick Meenan, blink-dev
Summed up the developer benefits of this change at https://jakearchibald.com/2016/link-in-body/

On Mon, 1 Feb 2016 at 15:27 Patrick Meenan <pme...@chromium.org> wrote:
--

vipxxx7...@gmail.com

unread,
Jan 29, 2017, 6:45:03 AM1/29/17
to blink-dev
Привет. Друг извеняй если отвлёк. Может ты мне поможешь? 100% Знаешь как такая проблема решается.в общем: мод.тел Fly_FS507 Android 6.O не могу войти в аккаунт,пишет на устройстве восстановлены настройки по умолчанию.
Reply all
Reply to author
Forward
0 new messages