Created attachment 56644 [details] [IMAGE] Web Inspector Shows Waiting for a useless media="print" resource HTML5 describes the <link> element's media attribute here: http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#attr-link-media > However, if the link is an external resource link, then the media attribute > is prescriptive. The user agent must apply the external resource when the > media attribute's value matches the environment and the other relevant > conditions apply, and must not apply it otherwise. If the browser is unaffected by the media queries in the <link media="..."> then it is safe to assume that the content is not immediately necessary and time could be better spent download other resources. Also, it may not be necessary to prevent the DOMContentReady or onload event's for the resource. In the attached image, the "print.css" file is a link with media="print". These styles do not affect the document, yet it was downloaded and delayed some events from firing.
This also happens for type="alternate stylesheet".
Firing load events before alternate stylesheets have loaded can easily have compatibility consequences - a script running from onload may want to switch stylesheets, for example. Even media="print" stylesheets are exposed via CSSOM. Loading them after other resources sounds like a great idea to me.
Antti, is this fixed now?
Antti, Alexei, Should we close this one in favor of Bug 243424
*** Bug 243424 has been marked as a duplicate of this bug. ***
<rdar://problem/102178226>
I’d like to move my initial comment from the bug, closed as duplicate, so it won’t be lost. Imagine a simple situation, two CSS files linked in the head: <link rel="stylesheet" href="screen.css"> <link rel="stylesheet" href="print.css" media="print"> Currently, WebKit will wait for both of them to be loaded before rendering anything at all. It makes sense since CSS is a render-blocking resource. But the browser won’t use print.css for rendering because the implicit “screen” media type doesn’t match the “print” value. And it’s clear from the HTML parsing stage: this resource is not render-blocking. Both Firefox and Chromium will keep loading print.css with lower priority and will start rendering once screen.css is available. It won’t save traffic but will make the page appear faster. The same could be used not only for printing but for many different applications, that would make CSS performance better: 1. Color scheme: dark.css should not block rendering if the current scheme is light <link rel="stylesheet" href="light.css" media="(prefers-color-scheme: light)"> <link rel="stylesheet" href="dark.css" media="(prefers-color-scheme: dark)"> 2. It could be possible to split CSS into separate files based on breakpoints <link rel="stylesheet" href="base.css"> <link rel="stylesheet" href="mobile.css" media="(max-width: 767px)"> <link rel="stylesheet" href="tablet.css" media="(min-width: 768px) and (max-width: 1023px)"> <link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)"> 3. It could be possible to offload some enhancements based on device properties or user preferences: <link rel="stylesheet" href="retina.css" media="(min-resolution: 2dppx)"> <link rel="stylesheet" href="heavy.css" media="(prefers-reduced-data: no-preference)"> <link rel="stylesheet" href="animation.css" media="(prefers-reduced-motion: no-preference)"> Well, it’s currently possible, but not in WebKit. Here’s the demo with breakpoints: https://pepelsbey.dev/articles/conditionally-adaptive/demo/index.html And the article, exploring the idea to use this behavior: https://pepelsbey.dev/articles/conditionally-adaptive/
Here’s another reason for this behavior to be aligned with the rest of the browsers. There’s a popular technique of CSS lazy loading introduced in Filament Group blog in 2019 https://www.filamentgroup.com/lab/load-css-simpler/ <link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'"> I see it used and mentioned here and there as one of the best and simplest option. The article states: > …the browser will load the stylesheet without delaying page rendering, asynchronously Which is not the case for Safari: it will be Render-blocking. No one seems to expect such incompatible behavior.
*** Bug 248724 has been marked as a duplicate of this bug. ***
There’s another use case for this behavior that might affect performance on some websites. This quite popular CSS lazy-loading trick doesn’t work in Safari: <link rel="stylesheet" href="critical.css" > <link rel="stylesheet" href="deferred.css" media="print" onload="this.media='all'" > <noscript> <link rel="stylesheet" href="deferred.css" > </noscript> All other browsers will render styles from critical.css and keep loading deferred.css in the background to apply them once they’re loaded. But Safari will wait for deferred.css and not render anything until it’s loaded. See more details in my the post https://pepelsbey.dev/articles/lazy-loading-safari/
Pull request: https://github.com/WebKit/WebKit/pull/9746
The issue is the we allow stylesheets with non-matching media delay the visually non-empty milestone. This only comes into play if the page is simple enough that it doesn't hit the milestone by having enough visual content to reach the threshold.
Nice! Does it affect CSS files loaded via @import? There’s a similar issue in Chromium https://bugs.chromium.org/p/chromium/issues/detail?id=1001078 These two should work the same: <link rel="stylesheet" href="/style.css" media="(prefers-color-scheme: light)"> <style> @import url(import.css) (prefers-color-scheme: light) </style>
(In reply to Vadim Makeev from comment #13) > Nice! Does it affect CSS files loaded via @import? There’s a similar issue > in Chromium https://bugs.chromium.org/p/chromium/issues/detail?id=1001078 > > These two should work the same: > > <link rel="stylesheet" href="/style.css" media="(prefers-color-scheme: > light)"> > > <style> > @import url(import.css) (prefers-color-scheme: light) > </style> No, worth a separate bug.
@Antti: The way I read your comment, it seems this bug only affects testcase-like pages. So not many real world pages should be affected. Am I understanding correctly? If that's the case, @Vadim, you may want to update your post to reflect that ?
> The way I read your comment, it seems this bug > only affects testcase-like pages. So not many > real world pages should be affected @Anthony Ricaud: There are at least two real-world use cases that I mentioned earlier in this issue. 1. Print styles that block rendering, although they’re not used 2. Lazy-loading technique that relies on the non-blocking behavior Both of them are not test case-like. > You may want to update your post to reflect that? I already updated the post to mention the PR with the fix. Otherwise, I think it’s still correct.
(In reply to Vadim Makeev from comment #16) > > The way I read your comment, it seems this bug > > only affects testcase-like pages. So not many > > real world pages should be affected > > @Anthony Ricaud: There are at least two real-world use cases that I > mentioned earlier in this issue. > > 1. Print styles that block rendering, although they’re not used > 2. Lazy-loading technique that relies on the non-blocking behavior > > Both of them are not test case-like. However, very few pages on the web are HTML files with an empty body element: _that_ is what is being called test case-like. Add a paragraph or two to the body, and behaviour should change, and you'll see the body straight away.
Oh, I see now, you’re right. I calculated that it takes a bit more than 200 characters to change the behavior. But with a typical modern SPAs setup, where you have empty <body> and a bunch of scripts, it might not be enough to trigger the proper behavior: <body> <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> <script src="app.js"></script> </body> This kind of page won’t get CSS loading benefits.
Committed 259963@main (9e31d4e46121): <https://commits.webkit.org/259963@main> Reviewed commits have been landed. Closing PR #9746 and removing active labels.
@Sam Sneddon: I updated the article, thank you! https://pepelsbey.dev/articles/lazy-loading-safari/#full-body