Intent to Implement and Ship: Stylesheets activated after the body is started do not block paint

663 views
Skip to first unread message

Patrick Meenan

unread,
May 26, 2016, 1:45:34 PM5/26/16
to blink-dev
pme...@chromium.org None External stylesheets in the body of the document or that get activated after the body has started to be parsed will no longer block paint. The parser will still block at a script tag until all prior stylesheets have loaded, including those in the body.

This change was implemented in Chrome 52 behind the Experimental Web Platform Features flag. This change allows for performance optimizations that the web performance community has been advocating for for a long time where developers can split their css between critical and below-the-fold and inline the critical css while loading the below-the-fold css after the above-the fold content. In principle that allows for rendering the critical part of the page with no additional round trips but in practice Blink blocks all rendering, even of the above-the-fold content as soon as it discovers the lower late-body css (usually well before it has painted any content at all).

There are Javascript hacks to work around the render blocking like loadcss and the proposed change matches the existing Firefox behavior (with Edge providing a slightly different variation but still allowing paint).
Firefox: Shipped Edge: No public signals Safari: No public signals Web developers: Strongly positive There is minimal risk of breaking any existing content. At worst there will be a flash of unstyled content for sites that have external sheets in the body. Those same sites will already encounter FOUC's with Firefox. None Yes None
crbug for paint-blocking issue: http://crbug.com/481122 https://www.chromestatus.com/features/5696805480169472 Yes

Chris Harrelson

unread,
May 26, 2016, 1:57:33 PM5/26/16
to Patrick Meenan, blink-dev
Have you considered issuing a console warning for at least one release that this behavior will change soon? I'm not as sure as you that there won't be a lot of websites with somewhat more flashing, though I agree it seems they won't actually break.

Also, what is the status of spec'ing this behavior and feedback from other browser vendors?

--
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,
May 26, 2016, 2:05:44 PM5/26/16
to Chris Harrelson, blink-dev
Console warning is easy enough to implement since the code to track if a sheet would be impacted by the change is all in one place.  I can also query the Alexa top-500k in Big Query from the HTTP Archive and get a sense for how often it shows up in the static HTML but that would only catch landing pages.

As far as spec goes, I'm not aware of any progress on it but the Firefox and Edge implementations are different enough that one of them would have to change to get consistency.  Feedback from Firefox on my earlier intent to implement the parser-blocking behavior of edge was positive though with a preference to implement Firefox's behavior.  There was no public opinion from Edge.  This is a necessary first step if we end up deciding to converge on the Edge behavior instead of the Firefox behavior.

Elliott Sprehn

unread,
May 26, 2016, 2:09:12 PM5/26/16
to Patrick Meenan, Chris Harrelson, blink-dev
On Thu, May 26, 2016 at 11:05 AM, 'Patrick Meenan' via blink-dev <blin...@chromium.org> wrote:
Console warning is easy enough to implement since the code to track if a sheet would be impacted by the change is all in one place.  I can also query the Alexa top-500k in Big Query from the HTTP Archive and get a sense for how often it shows up in the static HTML but that would only catch landing pages.

As far as spec goes, I'm not aware of any progress on it but the Firefox and Edge implementations are different enough that one of them would have to change to get consistency.  Feedback from Firefox on my earlier intent to implement the parser-blocking behavior of edge was positive though with a preference to implement Firefox's behavior.  There was no public opinion from Edge.  This is a necessary first step if we end up deciding to converge on the Edge behavior instead of the Firefox behavior.


Why is this a first step? It seems like switching directly to the Edge behavior doesn't have any risk associated with making pages FOUC. Shipping async sheets does have risk of making a bunch of blinking content. :) 

- E 

Rick Byers

unread,
May 26, 2016, 2:10:33 PM5/26/16
to Patrick Meenan, Chris Harrelson, blink-dev
Is there at least an issue filed in some W3C or WHATWG GitHub for the fact that the spec doesn't reflect implementations here?

Getting some data of the impact either from HTTPArchive or (better) UseCounters would be good.  If you're going to output a console warning anyway, you might as well make that a deprecation and consult the UMA data before changing it.  You believe you can tell reliably at runtime when this change will cause a FOUC?

Patrick Meenan

unread,
May 26, 2016, 2:14:49 PM5/26/16
to Rick Byers, Chris Harrelson, blink-dev
Reliably at runtime I can detect when a script-blocking stylesheet is activated after the body has started.  I can't detect if that will trigger a FOUC because there's no way to tell if the sheet includes any styles relevant to content in the viewport.  At best I can over-count and detect cases where it COULD cause a FOUC that wouldn't have been there before but not necessarily that it WILL cause one.

Patrick Meenan

unread,
May 26, 2016, 2:21:09 PM5/26/16
to Elliott Sprehn, Chris Harrelson, blink-dev
Implementation is a necessary first step.  The Edge behavior of blocking the parser still requires that we not block painting while the parser is blocked.  Actually shipping isn't necessary if we prefer to jump to the Edge behavior and ship that.  The Edge behavior doesn't eliminate the possibility of FOUC.  Anything in the DOM before the stylesheet was referenced that contains elements that will be styled by the later sheet will still flash.  It does prevent cases of FOUC for any content referenced after the sheet.

If we'd rather ship the Edge behavior then I can leave this behind a flag while we work on that.  That said, my first run at pausing the parser for sheets (and HTML imports which would also need to be paused after) was...challenging.  The state tracking for the parser and token streams have some edge cases which are riskier (for me) to be poking at.

Rick Byers

unread,
May 26, 2016, 2:28:46 PM5/26/16
to Patrick Meenan, Chris Harrelson, blink-dev
On Thu, May 26, 2016 at 2:14 PM, Patrick Meenan <pme...@google.com> wrote:
Reliably at runtime I can detect when a script-blocking stylesheet is activated after the body has started.  I can't detect if that will trigger a FOUC because there's no way to tell if the sheet includes any styles relevant to content in the viewport.  At best I can over-count and detect cases where it COULD cause a FOUC that wouldn't have been there before but not necessarily that it WILL cause one.

Makes sense, thanks.  So the only thing I'd caution against then is dramatically over-warning.  Eg. if you're over-counting by 10x then a warning message will probably do more harm (deprecation warning blindness / wasted effort) than good.  In which case we should still have a UseCounter to track the upper bound of risk, but ship without a warning but (as always) keep a close eye on user feedback in beta etc.

Patrick Meenan

unread,
May 26, 2016, 2:51:03 PM5/26/16
to Rick Byers, Chris Harrelson, blink-dev
As far as specs go, any recommendations where I should poke for specs about painting behavior?

There are a few WHATWG specs that get close and touch on parts of the behavior but none of them talk about rendering/painting (even for head sheets):
* External stylesheets are "body-ok" (allowed in the body)
* Styles that block scripts are spec'd
* Fetching of the sheets are spec'd
* The rendering spec doesn't appear to touch on when or how to paint
* I couldn't find anything relevant in the csswg spec

On Thu, May 26, 2016 at 2:10 PM, Rick Byers <rby...@chromium.org> wrote:

Philip Jägenstedt

unread,
May 27, 2016, 8:14:10 AM5/27/16
to Patrick Meenan, Ian Hickson, Rick Byers, Chris Harrelson, blink-dev
Is this change in any way observable to web content? Blocking the parser would be like Edge does would be, right?

I ask because however observable to end users, if it's not observable to scripts at all, then it's unsurprising if no spec touches upon this and I'm not sure which spec would.

Hixie, do you remember if you ever put anything in HTML related to painting?

Ian Hickson

unread,
May 27, 2016, 1:29:46 PM5/27/16
to Philip Jägenstedt, Patrick Meenan, Rick Byers, Chris Harrelson, blink-dev
I think this is one of those quality-of-implementation issues. I doubt any spec talks about it.

Patrick Meenan

unread,
May 27, 2016, 1:39:22 PM5/27/16
to Ian Hickson, Philip Jägenstedt, Rick Byers, Chris Harrelson, blink-dev
It should be completely transparent to scripts and unlikely to be observable from code.

I'm not 100% sure IE actually blocks the parser, they may just prevent the new nodes from getting added to the render tree if they are discovered after and external stylesheet (for blink, mirroring the behavior would be easiest if we actually paused the parser progress.  Even then, observability from code would be racy.  Any new script tags would still block the parser so it would take an existing script running a RAF or timer loop checking the DOM for progress and it would have to know that the HTML had actually arrived to the parser (maybe if it was document.written).

Elliott Sprehn

unread,
May 27, 2016, 11:42:36 PM5/27/16
to Patrick Meenan, Chris Harrelson, Rick Byers, Ian Hickson, Philip Jägenstedt, blink-dev

Edge (and I'm pretty sure IE) actually block the parser. This is observable by running a setTimeout loop and observing the DOM. See the snippets I posted on this bug.

The WebKit/Blink behavior today is confusing since we do some funny things around the first forced layout. The doc on the FOUC sanity meta bug describes this.

Long term we should either be async in the body or block the parser. I think the Edge behavior is least likely to break content and make it blink though. :)

Philip Jägenstedt

unread,
May 30, 2016, 9:15:52 AM5/30/16
to Elliott Sprehn, Patrick Meenan, Chris Harrelson, Rick Byers, Ian Hickson, blink-dev
Patrick, have you had a discussion with the relevant people for other engines to figure out what behavior to try converging on?

I guess that blocking the parser makes it easy to order the markup to get the intended behavior, but are there worthwhile things that could be achieved if there was no blocking at all?

Patrick Meenan

unread,
May 30, 2016, 3:51:38 PM5/30/16
to Philip Jägenstedt, Elliott Sprehn, Chris Harrelson, Rick Byers, Ian Hickson, blink-dev
I don't know the relevant people to chat with about it for the other engines.  I'll file an issue on the whatwg html tracker to start discussion on the blocking of the parser.  From the sounds of it, the "when to paint" part doesn't currently fall into any of the groups' domain.

The only thing that comes to mind with no blocking at all is you could get a little more control over blocking though it's more implicit and relies on the fact that the parser will block at the next script tag.  You could emulate the current Edge behavior by putting a script tag after in-body external sheets but that does feel a bit bizarre.  By not blocking you could have a collection of in-body sheets followed by a script tag and have the parser process all of them and then block until they all finish.  Only real benefit I can think of for that case though is if the sheets @import other sheets.  By loading them async the parser will not get stuck serializing the imports (which are largely not handled by Chrome's preload scanner currently).  That's a pretty edge case of an edge case though.

Whatever the behavior there is likely to be some impact on the behavior for HTML imports as well.  Blocking the parser for css will probably also mean blocking the parser for imports and the dependency serializing becomes a bigger issue there.

Patrick Meenan

unread,
May 30, 2016, 4:00:56 PM5/30/16
to Philip Jägenstedt, Elliott Sprehn, Chris Harrelson, Rick Byers, Ian Hickson, blink-dev

Elliott Sprehn

unread,
May 30, 2016, 5:15:57 PM5/30/16
to Patrick Meenan, Chris Harrelson, Rick Byers, Ian Hickson, Philip Jägenstedt, blink-dev

I don't think we should worry too much about the current html imports. The only reason they need to block painting is because of the behavior where imports can apply stylesheets. That behavior will never be added to the future html modules (which can't apply styles and are deferred by default).

We should continue with the FOUC avoidance sanity plan:
- don't block the parser until we undefer commits. This code is now in core so it's easy to connect to the parser.
- never block the parser on html imports
- don't undefer commits until parser inserted imports or sheets that were inserted before the body are done loading.

That will avoid FOUC, keep the parallelism for all html imports, and greatly simplify the system. It also shouldn't have any FOUC risks like making all sheets async.

Patrick Meenan

unread,
May 31, 2016, 9:46:27 AM5/31/16
to Elliott Sprehn, Chris Harrelson, Rick Byers, Ian Hickson, Philip Jägenstedt, blink-dev
Discussing it on the whatwg github issue but as Boris points out, the Edge behavior is against the current spec which calls for link tags to not block the parser and doesn't treat head/body differently.  I'll get a usage counter added and work on an implementation for the Edge behavior for the parser in case the spec moves in that direction.  I'm also trying to reach out to the Webkit team to see if they would be comfortable implementing either behavior.

Boris Zbarsky

unread,
May 31, 2016, 10:18:06 AM5/31/16
to blink-dev
On 5/30/16 9:15 AM, Philip Jägenstedt wrote:
> but are there worthwhile things that could be
> achieved if there was no blocking at all?

Absolutely. Consider this, in <body>:

<link rel="stylesheet" href="sheet1.css">
Various stuff not including <script>.
<link rel="stylesheet" href="sheet2.css">
More stuff

When do the loads of subresources sheet2 links to (e.g. @imports or
background images from it) start loading? If you block the parser on
sheet 1, they can't start loading until sheet1 is loaded without adding
some sort of special codepaths to prefetch those subresources. And
those specialy codepaths might not work correctly for background images
anyway, since those loads tend to only happen when some node matches the
rule...

If you don't block, things from sheet2 can load in the normal way.

In other words, blocking inherently gives up some parallelism. Parts of
it can probably be recovered with enough pain and suffering by UAs,
using various non-standardized heuristics and whatnot. But it adds
significant implementation complexity and more nonstandard things that
are needed in practice to create a useful UA...

-Boris

Elliott Sprehn

unread,
May 31, 2016, 3:39:06 PM5/31/16
to Boris Zbarsky, blink-dev
On Tue, May 31, 2016 at 7:17 AM, Boris Zbarsky <bzba...@mit.edu> wrote:
On 5/30/16 9:15 AM, Philip Jägenstedt wrote:
but are there worthwhile things that could be
achieved if there was no blocking at all?

Absolutely.  Consider this, in <body>:

   <link rel="stylesheet" href="sheet1.css">
   Various stuff not including <script>.
   <link rel="stylesheet" href="sheet2.css">
   More stuff

When do the loads of subresources sheet2 links to (e.g. @imports or background images from it) start loading? 

@import is loaded by the preload scanner, background images are deferred until the first style recalc that would match that rule.
 
If you block the parser on sheet 1, they can't start loading until sheet1 is loaded without adding some sort of special codepaths to prefetch those subresources.

That already exists, it's the preload scanner, and I believe all browsers have it in some manner. The win from it was also so large I can't imagine anyone removing it. It seems reasonable to assume that browsers will implement a preload scanner (or some equivalent optimization), and that it's a part of the web:

 
And those specialy codepaths might not work correctly for background images anyway, since those loads tend to only happen when some node matches the rule...

Indeed, browsers only fetch resources declared in style rules on the first usage of them. This is what authors expect as well. Anything that started prefetching images from sheets without waiting on other pending sheets would likely start download images in rules that have overrides in other sheets.


If you don't block, things from sheet2 can load in the normal way.

In practice WebKit and Blink don't do that, they pretend content is display: none since the content after sheet1.css may depend on the styles in it, otherwise we FOUC. Edge blocks the parser here. I believe Gecko is the only engine that would FOUC that content today.


In other words, blocking inherently gives up some parallelism.

I don't think there's anything inherent about it, the preload scanner exists in all browsers, without it you'd load body resources too late and take a nasty perf hit for scripts or images in the body.
 
Parts of it can probably be recovered with enough pain and suffering by UAs, using various non-standardized heuristics and whatnot.  But it adds significant implementation complexity and more nonstandard things that are needed in practice to create a useful UA...

I don't think this is any worse than needing a preload scanner, which everyone has already. Especially given that both Blink and WebKit pretend the content is display: none, and IE and Edge block the parser, so most browsers are not fetching resources in the situations you describe. **

** This is not quite accurate, the behavior in WebKit/Blink is racy and buggy, so we do fetch sometimes, but it's hardly something authors can predict or understand. We've had years of complaints. The whole purpose of this project is to make the behavior not racy and instead make it predictable for authors. FOUC is frustrating, especially when you can't figure out why it works sometimes (ex. warm cache, network slowness, etc.).

- E 

Boris Zbarsky

unread,
May 31, 2016, 3:46:59 PM5/31/16
to Elliott Sprehn, blink-dev
On 5/31/16 3:38 PM, Elliott Sprehn wrote:
> @import is loaded by the preload scanner

Last I checked this is only the case for <style> in Blink, no? Not for
external stylesheets. Please do look at the actual example I suggested.

> background images are deferred
> until the first style recalc that would match that rule.

Precisely, and if you block the content that would match that rule from
being in the DOM, you don't get that style recalc until much later.

> If you block the parser on sheet 1, they can't start loading until
> sheet1 is loaded without adding some sort of special codepaths to
> prefetch those subresources.
>
> That already exists, it's the preload scanner, and I believe all
> browsers have it in some manner.

See above.

Note that Gecko's preload scanner does not parse inline stylesheets, by
the way. We can obviously fix that, but my larger point is that
blocking the parser requires a lot more than the sort of preload scanner
browsers typically already have, simply to get the parallelism you get
for free with not blocking the parser.

> Indeed, browsers only fetch resources declared in style rules on the
> first usage of them. This is what authors expect as well. Anything that
> started prefetching images from sheets without waiting on other pending
> sheets would likely start download images in rules that have overrides
> in other sheets.

That's actually not terribly likely to be a problem in practice, I expect.

> I don't think there's anything inherent about it

See above.

> I don't think this is any worse than needing a preload scanner, which
> everyone has already.

It's definitely worse, because it involves a lot more than just scanning
the HTML.

> so most browsers are not fetching resources in the situations you
> describe.

That's not true for @import in non-inline sheets.

-Boris

Elliott Sprehn

unread,
May 31, 2016, 4:21:17 PM5/31/16
to Boris Zbarsky, blink-dev
On Tue, May 31, 2016 at 12:46 PM, Boris Zbarsky <bzba...@mit.edu> wrote:
On 5/31/16 3:38 PM, Elliott Sprehn wrote:
@import is loaded by the preload scanner

Last I checked this is only the case for <style> in Blink, no?  Not for external stylesheets.  Please do look at the actual example I suggested.

We have plans to expand support for @import.
 


background images are deferred
until the first style recalc that would match that rule.

Precisely, and if you block the content that would match that rule from being in the DOM, you don't get that style recalc until much later.

We don't today anyway, since we pretend the content is display: none.
 


    If you block the parser on sheet 1, they can't start loading until
    sheet1 is loaded without adding some sort of special codepaths to
    prefetch those subresources.

That already exists, it's the preload scanner, and I believe all
browsers have it in some manner.

See above.

Note that Gecko's preload scanner does not parse inline stylesheets, by the way.  We can obviously fix that, but my larger point is that blocking the parser requires a lot more than the sort of preload scanner browsers typically already have, simply to get the parallelism you get for free with not blocking the parser.

There's no free parallelism, we pretend the content is display: none.
 


Indeed, browsers only fetch resources declared in style rules on the
first usage of them. This is what authors expect as well. Anything that
started prefetching images from sheets without waiting on other pending
sheets would likely start download images in rules that have overrides
in other sheets.

That's actually not terribly likely to be a problem in practice, I expect.

We've had many complaints about this. Authors load base-theme.css, and then theme-overrides.css, if you don't have both of them loaded you'll download the images for base-theme incorrectly.
 

I don't think there's anything inherent about it

See above.

I don't think this is any worse than needing a preload scanner, which
everyone has already.

It's definitely worse, because it involves a lot more than just scanning the HTML.

We'll probably need that eventually anyway, for example scanning for @font-face can be a large win to avoid showing blank text while a font downloads.


so most browsers are not fetching resources in the situations you
describe.

That's not true for @import in non-inline sheets.

Indeed, I think we should try this and see how it works out though. Blocking the parser is very unlikely to break any content in WebKit/Blink/Edge or IE. Standardizing the Firefox behavior is full of risk though, it means any content which depended on the display: none or parser blocking of those four engines is going to FOUC.

Given that there's no agreement between engines, and that we've gone many years being inconsistent, I don't think we should worry about the standard just yet. We can experiment to see what behavior is the best.

- E 

Boris Zbarsky

unread,
May 31, 2016, 9:49:55 PM5/31/16
to blink-dev
On 5/31/16 4:20 PM, Elliott Sprehn wrote:
> There's no free parallelism, we pretend the content is display: none.

You're carefully ignoring the @import bit, yes?

Either that or we're seriously talking past each other.

> We've had many complaints about this. Authors load base-theme.css, and
> then theme-overrides.css, if you don't have both of them loaded you'll
> download the images for base-theme incorrectly.

Sure. But are authors doing that from inside <body>?

Also, note that we were talking about the following situation if I
understood correctly:

1) There are two stylesheets.
2) The earlier stylesheet overrides rules from the later one.
3) There is content between the two stylesheets that both sets of rules
apply to.

Or did I misunderstand?

> We'll probably need that eventually anyway, for example scanning for
> @font-face can be a large win to avoid showing blank text while a font
> downloads.

See my point in the spec issue: if we're going to lean so much on the
preload scanner, we need to spec it so UAs don't have to guess what
needs to be implemented to be web-compatible in practice.

> so most browsers are not fetching resources in the situations you
> describe.
>
> That's not true for @import in non-inline sheets.
>
>
> Indeed, I think we should try this and see how it works out though.

One thing I should note: Gecko _does_ in fact load @import inside
stylesheets loaded by the preload scanner. So that's not even an issue
for us. But it's not clear to me that this should be a hard requirement
for web browsers in general....

> Blocking the parser is very unlikely to break any content in
> WebKit/Blink/Edge or IE.

Sure. It'll just make it load slower or require a lot more complexity
to make it load just as fast. ;)

> Standardizing the Firefox behavior is full of
> risk though, it means any content which depended on the display: none or
> parser blocking of those four engines is going to FOUC.

That's true, if you hit all the things just wrong.

In practice, I believe we have gotten precisely zero but reports about this.

> We can experiment to see what behavior is the best.

Sure.

-Boris

Rick Byers

unread,
Jun 21, 2016, 1:50:03 PM6/21/16
to Boris Zbarsky, pme...@chromium.org, blink-dev
Patrick, so what do you want to do with this intent?  Do you want to move forward with this as planned?  I tend to agree with Elliot's point that it's probably OK to experiment with some changes here before we worry too much about locking down the spec.

Rick

Elliott Sprehn

unread,
Jun 21, 2016, 2:03:46 PM6/21/16
to Rick Byers, Boris Zbarsky, Patrick Meenan, blink-dev
On Tue, Jun 21, 2016 at 7:49 PM, Rick Byers <rby...@chromium.org> wrote:
Patrick, so what do you want to do with this intent?  Do you want to move forward with this as planned?  I tend to agree with Elliot's point that it's probably OK to experiment with some changes here before we worry too much about locking down the spec.



I met with bz about this to discuss the plan. In general browsers all disagree about what to do for stylesheets inserted in the head vs the body, <link> vs @import, and when to run requestAnimationFrame. I now understand his concern about @import, which Firefox doesn't block painting on, but given that other browsers do I think we're fine to change our behavior for now. We should also get numbers on how often pages force a layout with pending sheets since that would cause FOUC in Firefox, yet they don't hear lots of complaints. Perhaps there's something we're missing there. :) We should also look into getting a preload scanner spec so other browsers don't need to reverse engineer our optimizations. At this point all browsers have a scanner, so it seems a part of the web.

Here's my research:

Gecko:
    - block painting on sheets in head, anything that forces a style recalc results in FOUC.
    - Don't ever block painting on @import, even in <head>.
    - Give a FOUC answer to JS, and FOUC paint when triggered.
    - Start running requestAnimationFrame immediately even if we're not painting.

WebKit:
    - Block painting for both head and body, even for @import.
    - Give a FOUC answer to JS but don't paint. Buggy edge cases.
    - Start running requestAnimationFrame immediately even if we're not painting.

Edge:
    - Block painting for all sheets in <head>.
    - Block parser for all <link> sheets, don't block for @import.
    - Apply @import styles as they come in, non-atomic.
    - Start running requestAnimationFrame immediately even if we're not painting.
    - Give a FOUC answer to JS, but don't paint, but only for <head> sheets.

Blink:
    - Block painting for both head and body, even for @import.
    - Give a FOUC answer to JS but don't paint. Buggy edge cases.
    - Don't start running requestAnimationFrame until all sheets are loaded and we're in the <body>.

The long term plan here was to change Blink to:
- Block painting on all sheets in the head.
- Block the parser on sheets in the <body>.
- Don't start running requestAnimationFrame until we start painting.

This is more rational and simpler than what we have today where we pretend content is display: none, but return values to JS when forced, but still skip painting it even though we did compute the style, even bz commented that sounds "complicated' :P.

I think we should experiment with this simpler model and see what impact is has on existing content, and the programming model. For async sheets I think we should instead consider adding an async keyword to <style> and <link> so it's not just @import getting the optimization, and not just in one browser.

- E 

Boris Zbarsky

unread,
Jun 21, 2016, 2:35:54 PM6/21/16
to Elliott Sprehn, Rick Byers, Patrick Meenan, blink-dev
On 6/21/16 2:03 PM, Elliott Sprehn wrote:
> Gecko:
> - block painting on sheets in head, anything that forces a style
> recalc results in FOUC.
> - Don't ever block painting on @import, even in <head>.

You mean @import in inline sheet or in external sheet?

We should be blocking painting on @import in external sheet (basically
because we don't consider the external sheet loaded until all its
imports re loaded). We may not be doing so on @import in inline sheet.

-Boris

Elliott Sprehn

unread,
Jun 21, 2016, 2:57:42 PM6/21/16
to Boris Zbarsky, blink-dev, Patrick Meenan, Rick Byers

Yeah on an internal sheet. I can run the tests again checking external sheets too. I'll get my test setup up on github so folks can try it as well.

- E

Rick Byers

unread,
Jun 21, 2016, 4:26:13 PM6/21/16
to Elliott Sprehn, Boris Zbarsky, blink-dev, Patrick Meenan
Thanks for all the research / discussion Elliott!  Sounds like a reasonable next step to me.  We'll learn more by trying this and can then circle back on how best to converge on interop.  LGTM1.

Philip Jägenstedt

unread,
Jun 22, 2016, 11:41:21 AM6/22/16
to Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev, Patrick Meenan
LGTM2. The suggested behavior sounds like it'll be easier to reason about, but it's quite hard to judge the risk here. Hope it works out :)

Jochen Eisinger

unread,
Jun 22, 2016, 11:54:34 AM6/22/16
to Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev, Patrick Meenan

lgtm3

Patrick Meenan

unread,
Jun 24, 2016, 11:54:05 AM6/24/16
to Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev, Patrick Meenan
Sorry about the delay, just getting back from Velocity.  Just a quick check on the LGTM's, those are for the plan Elliott outlined, correct?

The long term plan here was to change Blink to:
- Block painting on all sheets in the head.
- Block the parser on sheets in the <body>.
- Don't start running requestAnimationFrame until we start painting.

If so then I'll go ahead and proceed with blocking the parser for the in-body external styles.  As far as specs go, I can add a note to the issue that we're proceeding with implementing the Edge behavior and kick off some discussions about adding an async attribute for the Firefox behavior.

Chris Harrelson

unread,
Jun 24, 2016, 12:11:28 PM6/24/16
to Patrick Meenan, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev
Hi Patrick,

I'm a little unsure what the exact new plan is, in terms of differences from today's behavior and updated summary of compatibility. Could you summarize it more explicitly? Are you proposing to directly implement the long-term plan?

Thanks,
Chris

Patrick Meenan

unread,
Jun 24, 2016, 12:24:49 PM6/24/16
to Chris Harrelson, Patrick Meenan, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev
Yes, I can directly implement the long-term plan. The current code behind a flag was necessary to be able to continue painting if we block the parser in the body.  Adding the parser blocking will take care of the first 2 bullets. 

I don't know the current state of RAF but I can tackle any change needed there as well. 

Chris Harrelson

unread,
Jun 27, 2016, 1:38:40 PM6/27/16
to Patrick Meenan, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev
Ok. LGTM from me to implement and experiment, but I'm concerned about a lack of spec w/ consensus among vendors for what compat behavior should be, before shipping. The behavior of the loading sequence is very important to spell out, and as evidenced by this thread, has quite a bit of subtlety and potentially unexpected behavior.

Chris

Patrick Meenan

unread,
Mar 9, 2017, 10:14:21 AM3/9/17
to Chris Harrelson, Patrick Meenan, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky, blink-dev
Following up on this intent now that the implementation has evolved.  As of the end of January (2017) our experimental implementation has matched the Edge behavior where in-body external stylesheets block the parser (and render) for content after the link tag but content before it is free to continue rendering.  As of this morning WebKit implements similar behavior and only blocks render for elements defined after the body stylesheets.

Our implementation has been behind the experimental web platform features flag and has been the default on the bots for the past 6 months.

What would be the best next steps? Some options that come to mind:
- Enable on Canary
- Run a finch trial to see impact on First Meaningful Paint or other metrics

If a reasonable number of sites are impacted I'd expect FMP to improve but realistically I don't expect a lot of existing sites to benefit.  Most that use the lazy-loading CSS techniques for performance already have the necessary hoops in place to use loadCSS or a similar library to load it asynchronously.

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+unsubscribe@chromium.org.



akoi...@gmail.com

unread,
Mar 9, 2017, 11:38:33 AM3/9/17
to blink-dev, chri...@chromium.org, pme...@chromium.org, joc...@chromium.org, foo...@chromium.org, rby...@chromium.org, esp...@chromium.org, bzba...@mit.edu


On Thursday, March 9, 2017 at 5:14:21 PM UTC+2, Patrick Meenan wrote:
Following up on this intent now that the implementation has evolved.  As of the end of January (2017) our experimental implementation has matched the Edge behavior where in-body external stylesheets block the parser (and render) for content after the link tag but content before it is free to continue rendering.  As of this morning WebKit implements similar behavior and only blocks render for elements defined after the body stylesheets.

Right. WebKit implementation does not block the parser. Instead it blocks style resolution and renderer construction after the first pending body stylesheet. In case a layout query forces full renderer construction we block painting for such renderers (to avoid FOUC). This is essentially just a tweak to our existing model of handling pending stylesheets. 

I think parser blocking may be unnecessarily big of a hammer to get the desired behavior.


  antti

Patrick Meenan

unread,
Mar 9, 2017, 12:03:52 PM3/9/17
to akoi...@gmail.com, blink-dev, Chris Harrelson, pme...@chromium.org, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky
I don't know the webkit patch well enough to know the side-effects but the biggest benefit for blocking the parser is that layout, styles, etc can continue to change for the parts of the page that existed before the external stylesheet was referenced (say, as images and fonts load).  We also no longer need to worry about blocking anything to avoid FOUC because the unstyled elements don't exist on the DOM yet.

Patrick Meenan

unread,
Mar 27, 2017, 9:31:48 AM3/27/17
to akoi...@gmail.com, blink-dev, Chris Harrelson, pme...@chromium.org, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky
Sorry for the delay, finally dug out my Mac so I could test the WebKit implementation and it fails in the ways I expected.

I have a few test pages linked from here.  The ones of particular interest are "External CSS at middle of Body" and "External CSS at end of Body".  In both cases there is a document that looks roughly like this:

<head></head>
<body>
<image that takes 1 second to load (server-side delay)>
<image that loads immediately>

There is a CSS file (either between the two images or after the last image) that takes 5 seconds to load that changes the body background to black so you can tell when it has loaded.  In both cases you would expect to see the first image load and render while the CSS is loading and then change the body background to black.  In the "middle" case you expect the second image to only render after the CSS has loaded but in the "end" case you expect to see it render immediately (before the first image).

In both cases WebKit doesn't render the 1-second delayed image until after the css has loaded.

Blocking the parser is also not that heavy of a hammer in this case because the parser would have to stop anyway at the next script tag it encountered and wait for the CSS to finish loading anyway.  It also makes the underlying layout/paint states a lot easier to reason about (never going back into a blocking state) and makes it much easier for developers/users to reason about.

All that said, it looks like something has broken in the latest canaries and the rendering isn't unblocking like it is supposed to (stable has the pre-blocking part that behaves like the Mozilla implementation).  I'll need to track down what else changed that broke the experimental path.



On Thu, Mar 9, 2017 at 11:38 AM, koiv...@iki.fi <akoi...@gmail.com> wrote:

Rick Byers

unread,
Mar 27, 2017, 12:05:43 PM3/27/17
to Patrick Meenan, Chris Harrelson, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky
Thanks for continuing to push on this Patrick!
I think you want to work with Chris or someone else on the paint team to formulate the plan for shipping a change here.  Ideally we'd be proposing some spec improvements / interop tests to try to nudge the engines on a path to convergence here.  But I defer to Chris on what the bar should be for shipping any specific change along the path - we don't want perfect to be the enemy of "better".

Rick

Rick Byers

unread,
Mar 27, 2017, 2:26:02 PM3/27/17
to Patrick Meenan, Chris Harrelson, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Eddy Mead
To be clear, my LGTM from June still stands.  Moving closer to Edge seems low enough risk that I don't personally see any reason why we'd need to block shipping on improving the spec situation here (though we definitely need to be on the look-out for reports of issues in the wild and be ready to re-evaluate).  But Chris had some concerns with that plan back in June.  Chris, what's your current thinking on what specifically you'd like to see before we try shipping a change here?

Also note I was wrong about this being a paint-team thing (sorry - forgot the history and skimmed the thread too quickly).  I do still want to know what team owns this space long term.  I.e. who owns the decision of what spec / interop work, if any, will be prioritized over the next year or so after we've realized the performance win? 

 

Antti Koivisto

unread,
Mar 27, 2017, 7:30:40 PM3/27/17
to Patrick Meenan, blink-dev, Chris Harrelson, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky
Which version of WebKit did you use? I tried these tests and they seem to work as expected (images appear at right times) in the latest Safari Technology Preview (26). The behaviour has not yet shipped outside STP.

Note that the patch was out of the WebKit tree for the last few days due to some performance issues (https://webkit.org/b/149157 for details) but it is now back in.


  antti

Patrick Meenan

unread,
Mar 28, 2017, 7:52:32 AM3/28/17
to Antti Koivisto, Patrick Meenan, blink-dev, Chris Harrelson, Jochen Eisinger, Philip Jägenstedt, Rick Byers, Elliott Sprehn, Boris Zbarsky
Ah, thanks - I was using the latest WebKit nightly at the time so probably caught the window at a bad time.  I'll take a closer look at the patch itself to see how it translates to blink and if any side-effects jump out.  One of the things we were looking forward to doing was simplifying the render state logic so hopefully it doesn't add more complexity to that.  I'm glad to hear the user/developer-facing behavior is effectively the same - that will make the best practices message a lot cleaner when it has rolled out.

Chris Harrelson

unread,
Mar 28, 2017, 9:44:49 PM3/28/17
to Rick Byers, Patrick Meenan, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Eddy Mead
On Mon, Mar 27, 2017 at 11:25 AM, Rick Byers <rby...@chromium.org> wrote:
To be clear, my LGTM from June still stands.  Moving closer to Edge seems low enough risk that I don't personally see any reason why we'd need to block shipping on improving the spec situation here (though we definitely need to be on the look-out for reports of issues in the wild and be ready to re-evaluate).  But Chris had some concerns with that plan back in June.  Chris, what's your current thinking on what specifically you'd like to see before we try shipping a change here?

I think my original concern still stands. I don't think we should ship new behavior without a spec story. I think we need at least a strong vision doc explaining why this change will result in good performance and ergonomics, and that other vendors & experienced developers (Facebook? Others?) agree that it scales to complicated sites in the best way. Fast/scalable loading is very important to the web, and so is predictability of what will happen during that loading. 

To further clarify my position, I see no reason why the proposal in this intent is the wrong path. It sounds good to me, and does sound like it reduces compat issues between browsers. But I think this space is important enough to get it right the first time (maybe run an intent to experiment?). I also think that no matter what, changing these semantics will break some content, probably more than usual. It's worth it to fix the loading story, but again we should do it right and not break things twice.


Also note I was wrong about this being a paint-team thing (sorry - forgot the history and skimmed the thread too quickly).  I do still want to know what team owns this space long term.  I.e. who owns the decision of what spec / interop work, if any, will be prioritized over the next year or so after we've realized the performance win? 

I am not sure of the current status either.

Thanks all,
Chris

Eddy Mead

unread,
Mar 28, 2017, 11:59:38 PM3/28/17
to Chris Harrelson, Rick Byers, Patrick Meenan, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, domi...@chromium.org
Hmm, I guess the style team owns it, especially if you consider esprehn and rune as people who have the context who are part of my team. Although, if I look at the code in the linked CL, it's mostly in core/dom?

Patrick Meenan

unread,
Mar 29, 2017, 11:48:18 AM3/29/17
to Eddy Mead, Chris Harrelson, Rick Byers, Patrick Meenan, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, domi...@chromium.org
The style side of things (to not block painting) was done in a different CL ~10 months ago.  As far as breaking content, it should only change something that might have been racy before into something deterministic (i.e. if the HTML stream got chunked such that there was a delay before any in-body style tokens were received).

As far as the spec side of things go, is there a particular w3c group I should try to work with?  Render/paint doesn't have a good home and it falls somewhere between the CSS and HTML specs (parser and layout behaviors).

Dimitri Glazkov

unread,
Mar 29, 2017, 6:56:18 PM3/29/17
to Patrick Meenan, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, domi...@chromium.org
What would be the scope of work for writing such a spec? I share Chris' concern for better interoperability, but I am also worried that we might be looking at a multi-year effort -- as I understand it, this is not something that's well-specified or even has agreement across browser vendors.

:DG<

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.









Patrick Meenan

unread,
Mar 30, 2017, 11:09:58 AM3/30/17
to Dimitri Glazkov, Patrick Meenan, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
To get all of the browsers fully aligned would span at least a few different specs and probably some areas that aren't spec'd.  It covers the intersection of the parser, building the DOM and building a render tree.

Specifically, when a stylesheet is parsed in the body of a document (either link or style tags) and before it has been loaded and processed:
- Should DOM elements discovered after the stylesheet be added to the DOM? (IE/Edge: No, Firefox and Safari: Yes, Chrome CL: No)
- Should elements discovered after the stylesheet be added to a render tree (causing FOUC)? (IE/Edge/Chrome CL: N/A, Firefox: Yes , Safari: No)
- Should Layout/Render/Paint continue for elements discovered before the stylesheet? (Everyone: Yes - Shipping Chrome/Safari: No)

In general, anything about when to paint (or allow paint) isn't spec'd and is mostly tuned by everyone to minimize re-doing work as much as possible, reduce FOUC and still display content to the user as soon as possible but pretty much nothing about when rendering is or isn't supposed to happen lies in any specs (that I'm aware of anyway).


To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+unsubscribe@chromium.org.










Chris Harrelson

unread,
Mar 30, 2017, 12:03:08 PM3/30/17
to Patrick Meenan, Dimitri Glazkov, Eddy Mead, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
On Thu, Mar 30, 2017 at 8:09 AM, Patrick Meenan <pme...@chromium.org> wrote:
To get all of the browsers fully aligned would span at least a few different specs and probably some areas that aren't spec'd.  It covers the intersection of the parser, building the DOM and building a render tree.

Specifically, when a stylesheet is parsed in the body of a document (either link or style tags) and before it has been loaded and processed:
- Should DOM elements discovered after the stylesheet be added to the DOM? (IE/Edge: No, Firefox and Safari: Yes, Chrome CL: No)
- Should elements discovered after the stylesheet be added to a render tree (causing FOUC)? (IE/Edge/Chrome CL: N/A, Firefox: Yes , Safari: No)
- Should Layout/Render/Paint continue for elements discovered before the stylesheet? (Everyone: Yes - Shipping Chrome/Safari: No)

In general, anything about when to paint (or allow paint) isn't spec'd and is mostly tuned by everyone to minimize re-doing work as much as possible, reduce FOUC and still display content to the user as soon as possible but pretty much nothing about when rendering is or isn't supposed to happen lies in any specs (that I'm aware of anyway).

Hi Patrick, 

I agree with you that to date it seems browsers have applied what heuristics they can to optimize things during loading, while retaining "enough" compatibility. There also seem to be gray areas even post-load having to do with what happens when new DOM elements are added or changed that depend on external async-loadable resources like CSS, images, etc.

I'm not asking for all browsers to be fully aligned and it to be written down in all the relevent specs, before your change ships. Many intents ship without achieving that, and your case is harder than most because it seems there is a lack of specs to edit. Sorry about that. :(

But I do think we should start an effort, talk with web community stakeholders about the issues involved, get their feedback, figure out what is spec'ed and where we might put the specs over time, have a draft spec-like document that spells out the answers to all the yes/no questions you mentioned above, and get browsers to say whether they would be ok moving towards that spec over time, or if not why not.

Thanks-
Chris

Anne van Kesteren

unread,
Mar 31, 2017, 1:26:46 AM3/31/17
to Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Philip Jägenstedt, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
On Thu, Mar 30, 2017 at 5:09 PM, Patrick Meenan <pme...@chromium.org> wrote:
> To get all of the browsers fully aligned would span at least a few different
> specs and probably some areas that aren't spec'd. It covers the
> intersection of the parser, building the DOM and building a render tree.
>
> Specifically, when a stylesheet is parsed in the body of a document (either
> link or style tags) and before it has been loaded and processed:
> - Should DOM elements discovered after the stylesheet be added to the DOM?
> (IE/Edge: No, Firefox and Safari: Yes, Chrome CL: No)
> - Should elements discovered after the stylesheet be added to a render tree
> (causing FOUC)? (IE/Edge/Chrome CL: N/A, Firefox: Yes , Safari: No)
> - Should Layout/Render/Paint continue for elements discovered before the
> stylesheet? (Everyone: Yes - Shipping Chrome/Safari: No)
>
> In general, anything about when to paint (or allow paint) isn't spec'd and
> is mostly tuned by everyone to minimize re-doing work as much as possible,
> reduce FOUC and still display content to the user as soon as possible but
> pretty much nothing about when rendering is or isn't supposed to happen lies
> in any specs (that I'm aware of anyway).

I don't think that's actually true. HTML defines when rendering can
happen and it has to do so to make sure all kinds of events end up
being dispatched before that happens. HTML also defines the HTML
parser, <link rel=stylesheet>, and some amount of blocking related to
<script> elements. It could conceivably define this as well.

In particular you'd have to modify step 7 of
https://html.spec.whatwg.org/#event-loop-processing-model somehow. And
if you also want to block the DOM being created you could modify the
HTML parser for that. It would be some work, but it doesn't seem
enormously difficult on the face of it.


--
https://annevankesteren.nl/

Philip Jägenstedt

unread,
Apr 7, 2017, 12:01:09 PM4/7/17
to Anne van Kesteren, Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
Patrick, how do you view the prospects of standardization here? All of this web exposed at least in the sense that web developers need to adapt to it, and I presume at least some of it would be possible to test using web-platform-tests.

https://wiki.whatwg.org/wiki/Specs/todo is not really maintained, but if you would explain in a sentence what it is that's missing here spec-wise, what is it?

Jake Archibald

unread,
Apr 15, 2017, 6:10:09 AM4/15/17
to Philip Jägenstedt, Anne van Kesteren, Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
If we're wanting to go down the Safari TP model, we could do it like this:

A stylesheet is loading until it's stylesheet resource, and any inner @imported sheets load.

The parser has a list of parser-inserted stylesheets.

When a <link rel="stylesheet"> or <style> is discovered, it's added to the list of parser-inserted stylesheets.

Every node has a list of render-blocking stylesheets. When a node is created, its render-blocking stylesheets is a copy of the parser's parser-inserted stylesheets.

A node won't render while there are loading stylesheets in its render-blocking stylesheets.

This allows for the potentially weird behaviour:

<script>
setTimeout(() => {
  document.querySelector('p').after('Foo!')
}, 1000);
</script>
<link rel="stylesheet" href="slow-stylesheet.css">
<p>Hello</p>
<p>World</p>

…where text node "Foo" may render while the paragraph before it "Hello" is render-blocked. This doesn't feel like a big deal though - if you want parser-blocking behaviour, move the <script> after the <link>.

--
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.

Elliott Sprehn

unread,
Apr 17, 2017, 11:41:39 PM4/17/17
to Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, akoi...@gmail.com, blink-dev, Jochen Eisinger, Boris Zbarsky, Shane Stephens, Dominic Cooney
On Sat, Apr 15, 2017 at 3:09 AM, Jake Archibald <jakear...@google.com> wrote:
If we're wanting to go down the Safari TP model, we could do it like this:

I don't think we should go with the Safari TP behavior for a number of reasons which is why our discussion has been around either the Firefox behavior (making sheets async), or the Edge behavior (block the parser). It was decided that blocking the parser had really nice developer ergonomics which is why we landed there.
To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+unsubscribe@chromium.org.

Antti Koivisto

unread,
Apr 18, 2017, 10:21:23 AM4/18/17
to Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
The current STP behaviour is 

- When resolving style, elements are styled normally until first element with loading stylesheet (in tree order) is encountered. 
- In case of a normal style resolution styles for further unstyled elements are not computed (and so no new renderers are constructed). 
- In case a script queries layout-dependent properties while there are still pending stylesheets (good old updateLayoutIgnorePendingStylesheets) we resolve style for all elements. Any new styles for elements after loading stylesheets are marked with 'non-final' bit. 
- Renderers with 'non-final' bit set are not painted to avoid FOUC.
- Completing stylesheet load will trigger style resolution that clears 'non-final' styles as needed.

If all stylesheets are in head then this reduces to the current WebKit (and I think Blink too) behavior.

Does the suggested parser blocking behavior mean you would block parser for head stylesheets too? 


    antti

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+unsubscribe@chromium.org.

Patrick Meenan

unread,
Apr 18, 2017, 2:36:03 PM4/18/17
to Antti Koivisto, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Patrick Meenan, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
No, the parser blocking is only for external sheets referenced from the body.  When a new stylesheet is added, it checks to see if the current document has a body yet.  Stylesheets imported from other stylesheets inherit their parent's body position.  Stylesheets loaded before a body exists are considered "render blocking" and the existing logic is carried forward until all render-blocking stylesheets have loaded.  Any non-render-blocking stylesheet loads will pause the parser until they have finished loading.

Antti Koivisto

unread,
Apr 19, 2017, 9:32:50 AM4/19/17
to Patrick Meenan, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
So this introduces a major behaviour difference between "<link rel=stylesheet ...><body>" and "<body><link rel=stylesheet ...>". FOUC logic and the related complexity is still needed to deal with head stylesheets. This doesn't seem like a good approach to me.


  antti

You received this message because you are subscribed to a topic in the Google Groups "blink-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/a/chromium.org/d/topic/blink-dev/QC5iefctcag/unsubscribe.
To unsubscribe from this group and all its topics, send an email to blink-dev+unsubscribe@chromium.org.

Patrick Meenan

unread,
Apr 19, 2017, 11:23:02 AM4/19/17
to Antti Koivisto, Patrick Meenan, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Rick Byers, blink-dev, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
If we want to eliminate the FOUC logic entirely, the parser-blocking logic could also be extended to block on inserting the body until all of the pending render-blocking stylesheets have loaded.

Rick Byers

unread,
May 15, 2018, 12:27:55 PM5/15/18
to Patrick Meenan, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, sh...@chromium.org, Dominic Cooney
Thanks for pushing this along Patrick.

No approval is required to try an experiment in dev/canary.  If there's significant breakage, then I'd expect it to show up there.  But given that Safari and Edge have already shipped this, maybe we're not likely to learn much from just a dev/canary experiment?  Regardless you should feel free to enable for dev only (eg. either via finch or a release-block-beta bug tracking turning it back to 'experimental') if you expect you could learn something of value by doing so.

Do you have reason to think that this might impact Chrome's overall FCP 99th-percentile metric (or at least on slow networks)?  Having even a small improvement on that would be strong justification for pushing aggressively on this IMHO, and so that would argue for doing a finch trial to get us a concrete number to trade off against Chris's concerns about investing more on the specs first.  Or maybe you're saying that we're not likely to see much value until developers have more incentive to optimize their site for this?  I think you should feel free to do a finch trial (certainly in beta, maybe also in stable if the risk of developer confusion isn't too high) if you feel that's likely to get us hard data on the value of this change.

Regardless, I still think there's a good argument here that we should ship this change without blocking on anything more than some spec issues being filed with repro cases showing how the specs don't describe what implementations are doing in practice.  Chris, any change in your perspective on this?

On Tue, May 15, 2018 at 12:11 PM <pme...@chromium.org> wrote:
Reviving the somewhat-beaten horse since the fix for the last-known issue with the existing experiment just landed yesterday.

The current implementation (behind a flag) matches the Edge behavior:
- Pauses the parser for in-body stylesheets (but not head stylesheets)
- Does not block layout/paint for in-body stylesheets

As far as web developers are concerned, it should have the same effect as Safari and Edge where critical css can be inlined in the head for the viewport and an external css can be loaded in the body for the content later in the page (or site-wide css).

Long-term (after imports have been fully deprecated and removed) the plan is to pause the parser for all stylesheets, including those in the head which will allow for the removal of all of the FOUC avoidance logic.  I'd rather not wait for that to happen to ship the developer-facing functionality though because it will probably be another year before we're at that point.

Any opinions on the best way to move the experiment forward from this point?  The bulk of the code has been running on the bots and as an experimental web platform feature for the last year.  If we roll out using a finch experiment we may be able to see some FCP metrics improve in UKM if we can identify a few sites that include external styles in their body but for the most part the only way I expect we'll hear if it is breaking things or not is through developer feedback.

Yoav Weiss

unread,
May 15, 2018, 12:44:06 PM5/15/18
to Rick Byers, Patrick Meenan, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, sh...@chromium.org, Dominic Cooney
Do we have a sense of how much content would benefit from this optimization right now? (i.e. how much HTML currently has non-critical `<link rel=stylesheet>` in its body)

If there isn't much content already out there, the best we can hope from a trial is to see that this change is not regressing any important metrics. (but we shouldn't expect improvements until developers adopt this method to load stylesheets)

Patrick - do you have data about this behavior change with existing content (e.g. from WPT)?



--
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.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAFUtAY_-xQCCKt1uA0hZ7b-rVxALktac52XvaC%2BO%3Do3dX58SEQ%40mail.gmail.com.

Boris Zbarsky

unread,
May 15, 2018, 12:48:03 PM5/15/18
to Rick Byers, Patrick Meenan, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, sh...@chromium.org, Dominic Cooney
On 5/15/18 12:27 PM, Rick Byers wrote:
> But given that Safari and Edge have already shipped this

Have they?

The testcase I tried writing for this just now at
http://jsbin.com/lojafotefi/1/edit?html,output [1] doesn't show either
Edge or Safari blocking the parser for a <link rel="stylesheet"> inside
<body>... In fact, in Edge I see the text show up as black for a while
before the sheet loads and the text turns green.

-Boris

[1] The testcase with the stuff jsbin adds stripped out:

<!doctype html>
<script>
function logit() {
console.log(performance.now(), document.querySelector("#foo"));
}

var i = setInterval(logit, 500);
onload = () => {
clearInterval(i);
logit();
}
</script>
<body>
<link rel="stylesheet"

href="http://software.hixie.ch/utilities/cgi/test-tools/delayed-file?pause=5&mime=text%2Fcss&text=p+%7B+color%3A+green+%21important+%7D%0D%0A">
<p id="foo">Is this green?</p>
</body>

Patrick Meenan

unread,
May 15, 2018, 1:38:23 PM5/15/18
to Rick Byers, Patrick Meenan, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Boris Zbarsky, Shane Stephens, Dominic Cooney
It MAY impact Chrome's overall FCP 99th-percentile metric but it would probably be a stretch.  nytimes.com is the biggest site I know of that has a stylesheet reference in the middle of the body and mod_pagespeed might also insert link tags if enabled but most implementations I'm aware of use loadCSS to load the stylesheet in a non-render-blocking way through js.  For the most part I expect it will just make future site developments cleaner (and step us towards cleaning up the FOUC system internally).  I can run a scan across the HTML bodies from the HTTP Archive to see how common it is in the wild.

As far as specs to file the bugs against with repro cases, would the whatwg html spec be the most relevant or the w3c html spec (or something non-html?).

Patrick Meenan

unread,
May 15, 2018, 1:38:27 PM5/15/18
to Boris Zbarsky, Rick Byers, Patrick Meenan, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Argh.  I'll ping the Edge team to see if the change was intentional and when it happened.  I'm seeing the same thing with http://test.patrickmeenan.com/css/css_middle.html where it is now aligned with the Firefox behavior.

I don't have a Mac handy but I'll look at STP when I get home.

Yoav Weiss

unread,
May 15, 2018, 2:25:08 PM5/15/18
to Patrick Meenan, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
On Tue, May 15, 2018 at 7:38 PM Patrick Meenan <pme...@chromium.org> wrote:
Argh.  I'll ping the Edge team to see if the change was intentional and when it happened.  I'm seeing the same thing with http://test.patrickmeenan.com/css/css_middle.html where it is now aligned with the Firefox behavior.

I don't have a Mac handy but I'll look at STP when I get home.

Testing that for Safari, I see:
* White page with text immediately.
* First image after a second.
* BG color after 5 seconds.
* Second image also appears only after 5 seconds.

--
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,
May 16, 2018, 11:42:49 AM5/16/18
to Yoav Weiss, Patrick Meenan, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Sorry about the delay.  I updated the main test page I use with 2 stylesheets in the body with different delays to provide a bit more thorough of a test as well as added detection to see if the parser paused or not (checks to see if a DOM element at the end of the document is present early).  If you've already visited you may have to refresh to get the updated version.

The test page is basically structured like:
- head
- body
- Image 1 (1 second to load)
- External Stylesheet 1 (5 seconds to load, turns background red)
- Image 2 (Loads immediately)
- External Stylesheet 2 (10 seconds to load, turns background black)
- DIV for checking if parser is paused

Firefox 60:
- All page text shows up with a white background
- Five seconds later the background tuns red
- Five seconds later the background turns black and the second image loads
- One second later the first image loads
- Parser is NOT paused

Safari Tech Preview (11.2 release 55):
- Text up until the first CSS shows up with a white background
- One second later the first image shows up
- Nine seconds later, the background turns black, the rest of the page text shows up and the second image displays
- Parser is NOT paused

Edge 17 (Spring Creators Update):
- All page text shows up with white background
- Second image displays immediately after
- One second later the first image displays
- Four seconds later the background turns red
- Five seconds later the background turns black
- Parser is NOT paused

Chrome Canary with experimental features enabled:
Text up until the first CSS shows up with a white background
- One second later the first image displays
- Four seconds later the background turns red and the second image displays
- Five seconds later the background turns black
- Parser IS paused

Clearly the behavior is all over the place and would seriously benefit from standardizing.  Some quick notes:
- In talking to the Edge team, the current behavior in 17 is actually a parser bug and was unintentional (and broke a lot of other things).  Not yet sure when they fix it what their desired end state will be.  Edge 16 had the same behavior as Chrome Canary and IMHO is the easiest to reason about but I'm probably biased.
- Firefox looks like it may be lazy-loading the images after all stylesheets finish (including body stylesheets).  Otherwise the display order makes no sense.
- Safari's implementation looks like it stops adding things to the render tree if ANY sytlesheets are pending.  That's why it skips the intermediate display of the red page and holds all updates until after the 10-second stylesheet loads.

Boris Zbarsky

unread,
May 16, 2018, 12:08:05 PM5/16/18
to Patrick Meenan, Yoav Weiss, Rick Byers, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
On 5/16/18 11:36 AM, Patrick Meenan wrote:
> - Firefox looks like it may be lazy-loading the images after all
> stylesheets finish (including body stylesheets).

Network panel says the image loads are "blocked" until the slower sheet
finishes. I'm not sure where that blocking is happening (e.g. whether
it's due to pipelining on the same connection or whether it's some sort
of network prioritization mechanism), but if it would be useful I could
probably look that up.

-Boris

Patrick Meenan

unread,
May 16, 2018, 12:34:35 PM5/16/18
to Boris Zbarsky, Patrick Meenan, Yoav Weiss, Rick Byers, blink-dev, koiv...@iki.fi, Jake Archibald, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Pretty sure it's not same-connection or pipelining and it's being throttled in an internal scheduler somewhere.  I can ping Patrick McManus to see if he's aware of any prioritization experiments.  59 behaved slightly differently but still didn't send the image request for the 2nd (fast) image on the wire until after both css files finished loading (even though the connection it used for the request was available 5 seconds earlier): https://www.webpagetest.org/video/compare.php?tests=180516_BV_620fe12482f2b2a90c51d6e8a36f3aa6-r:1-c:0

I expect there is some prioritization experimentation going on similar to how Chrome throttles the loading of low-priority requests while render-blocking resources are still pending (speaking of which, Chrome's logic will likely need to be updated to lower the priority of body stylesheets and not consider them render-blocking if this lands).

Jake Archibald

unread,
May 17, 2018, 3:26:18 AM5/17/18
to Patrick Meenan, Yoav Weiss, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
What if the stylesheet is followed by <script> </script>? Does that block the parser on the style load in both Edge and Firefox?

Patrick Meenan

unread,
May 17, 2018, 8:56:45 AM5/17/18
to Jake Archibald, Patrick Meenan, Yoav Weiss, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Yes.  With an empty script tag after the styles all of the browsers behave the same and block the parser except Firefox still delays the second image until after the last stylesheet loads (presumably a separate issue).  This includes Safari because it doesn't discover the second stylesheet asynchronously since the parser blocks at the first script tag.

Patrick Meenan

unread,
May 17, 2018, 8:59:05 AM5/17/18
to Patrick Meenan, Jake Archibald, Yoav Weiss, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Test page with the script tags is here btw: http://test.patrickmeenan.com/css/css_middle_script.html

Patrick Meenan

unread,
May 17, 2018, 9:54:07 AM5/17/18
to Patrick Meenan, Jake Archibald, Yoav Weiss, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Proposed plan:

- After m68 branch, switch the feature from experimental to stable
- File a launch blocker bug for M69 to flip the flag back if not launch-approved
- Watch the relevant metrics through Canary/Dev/Beta

Assuming metrics look ok:
- Update intent-to-ship with the relevant data (or take a look at the updated launch process to see if there is anything else missing)
- Upon approval, close the launch blocker bug
- Remove the code to control the functionality at runtime and make the change permanent

If the metrics show any issues, flip the setting back to experimental and merge it into the M69 branch.

I'm assuming most of our messaging to developers will be to use the <link/><script> <script/> pattern to get consistent behavior across all of the browsers with the current implementations while we work on specifying the behavior.

Patrick Meenan

unread,
May 17, 2018, 10:22:48 AM5/17/18
to Patrick Meenan, Jake Archibald, Yoav Weiss, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
Looks like the test page was triggering Firefox's logic for tracking pixels because the images didn't have explicit dimensions.  I updated the test pages so the images have explicit dimensions and it now behaves like all of the other browsers with the script tag present and like it used to without the script tag (matching the current Edge behavior).

Yoav Weiss

unread,
May 17, 2018, 1:28:38 PM5/17/18
to Patrick Meenan, Jake Archibald, Boris Zbarsky, Rick Byers, blink-dev, koiv...@iki.fi, Philip Jägenstedt, Anne van Kesteren, Dimitri Glazkov, Eddy Mead, Chris Harrelson, Jochen Eisinger, Elliott Sprehn, Shane Stephens, Dominic Cooney
We discussed this intent & launch plan in the API owner meeting today. (Philip, Alex, Rick, Daniel and myself)

Since this thread already received the required LGTMs, no more LGTMs are needed.

On Thu, May 17, 2018 at 3:54 PM Patrick Meenan <pme...@chromium.org> wrote:
Proposed plan:

- After m68 branch, switch the feature from experimental to stable
- File a launch blocker bug for M69 to flip the flag back if not launch-approved
- Watch the relevant metrics through Canary/Dev/Beta

Landing this in M69 and watching for regression metrics LGTM (4?).
The launch blocker bug is more than what we usually require in similar cases, so it is up to you.

j.j.

unread,
Nov 2, 2018, 6:25:40 PM11/2/18
to blink-dev
This was not done yet, right? Any estimated date? (would solve a minor issue for me) 

Am Donnerstag, 26. Mai 2016 19:45:34 UTC+2 schrieb Patrick Meenan:
pme...@chromium.org None External stylesheets in the body of the document or that get activated after the body has started to be parsed will no longer block paint. The parser will still block at a script tag until all prior stylesheets have loaded, including those in the body.

This change was implemented in Chrome 52 behind the Experimental Web Platform Features flag. This change allows for performance optimizations that the web performance community has been advocating for for a long time where developers can split their css between critical and below-the-fold and inline the critical css while loading the below-the-fold css after the above-the fold content. In principle that allows for rendering the critical part of the page with no additional round trips but in practice Blink blocks all rendering, even of the above-the-fold content as soon as it discovers the lower late-body css (usually well before it has painted any content at all).

There are Javascript hacks to work around the render blocking like loadcss and the proposed change matches the existing Firefox behavior (with Edge providing a slightly different variation but still allowing paint).
Firefox: Shipped Edge: No public signals Safari: No public signals Web developers: Strongly positive There is minimal risk of breaking any existing content. At worst there will be a flash of unstyled content for sites that have external sheets in the body. Those same sites will already encounter FOUC's with Firefox. None Yes None
crbug for paint-blocking issue: http://crbug.com/481122 https://www.chromestatus.com/features/5696805480169472 Yes

Rune Lillesveen

unread,
Nov 5, 2018, 4:23:42 AM11/5/18
to fri...@jeka.info, blin...@chromium.org
This was enabled for M69. I see that chromestatus was not updated: https://www.chromestatus.com/feature/5696805480169472

--
You received this message because you are subscribed to the Google Groups "blink-dev" group.

Yoav Weiss

unread,
Nov 5, 2018, 4:27:53 AM11/5/18
to Rune Lillesveen, fri...@jeka.info, blin...@chromium.org
Thanks for confirming and notifying that the entry wasn't up-to-date. Just updated it.

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Rune Lillesveen

unread,
Nov 5, 2018, 5:12:36 AM11/5/18
to Yoav Weiss, fri...@jeka.info, blin...@chromium.org
I didn't test it thoroughly but the flag went "stable" 27th of May and I tried a couple of the demos in M70 which seemed to work.

fri...@jeka.info

unread,
Nov 7, 2018, 5:46:59 AM11/7/18
to blink-dev, fri...@jeka.info


Am Montag, 5. November 2018 10:23:42 UTC+1 schrieb Rune Lillesveen:
This was enabled for M69. I see that chromestatus was not updated: https://www.chromestatus.com/feature/5696805480169472

Hmm, I see now.
Tested this hoping the change would be compatible with Firefox, but its not.

Reply all
Reply to author
Forward
0 new messages