Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-fonts] Add a font-display keyword to eliminate @font-face FOIT & layout shifts #7271

Open
xiaochengh opened this issue May 11, 2022 · 30 comments

Comments

@xiaochengh
Copy link
Contributor

xiaochengh commented May 11, 2022

Currently, we don't have any easy & sound way to eliminate FOIT & layout shifts caused by web fonts:

  • font-display: optional elimintes layout shifts and FOIT, but at the cost that the web font may not be used, which limits its usage
  • Other font-display values do not reduce layout shifts at all
  • size-adjust descriptor only reduces the layout shift but can't guarantee 0 CLS, and there might still be a FOIT. It's also complicated to use since we need to find out the correct value.

I'm proposing adding a new keyword to the font-display descriptor, tentative named font-display: critical, which:

  • Turns the @font-face a critical subresource of the style sheet, and hence makes it block the load event of the style sheet
  • Makes UA start loading such a @font-face eagerly; other font faces are still loaded lazily when used
  • It has the same Font Display Timeline as font-display: block

In this way, as long as the @font-face is defined in a render-blocking style sheet (which everyone knows about but hadn't been specified until recently), then it will block the first render of the document, and hence eliminate FOIT / layout shifts.

This feature is supposed to be used on web fonts that are truly critical, so that developers want to eliminate FOIT / CLS at a great cost of delaying rendering. It will be footgun-ish and shouldn't be used arbitrarily.

Use cases

Basic usage:

<head>
  <style>
  @font-face {
    font-family: my-font;
    font-display: critical;
    src: url(/my-font.ttf);
  }
  body { font-family: my-font; }
  </style>
</head>
<body>
  Text in my-font with absolutely no FOIT / CLS
</body>

There's also a particular use case I'd like to support: making a 3rd party web font render-blocking without knowing the font url.

Developer page:

<head>
  <link rel=stylesheet href="https://3p-fonts.com/cool-font.css?critical=yes">
  <style>body { font-family: cool-font; }</style>
</head>
<body>
  Text in cool-font with absolutely no FOIT / CLS
</body>

https://3p-fonts.com/cool-font.css?critical=yes:

@font-face {
  font-family: cool-font;
  font-display: critical;
  /* url is maintained by 3p-fonts.com. May change at any time; may even be generated. */
  /* Developers shouldn't preload this url or inline this style sheet. */
  src: url(/some-random-hash-123654ABCFED-or-whatever.ttf);
}

Possible discussions

  • Q: How about preloading the font?
  • A: Preloading just makes it less likely to cause FOIT / layout shifts, but there's no guarantee. And it doesn't work for the 3rd party web font use case.
  • Q: How about adding blocking=render to the font preload <link> to block rendering until the preload finishes?
  • A: Besides not working for 3rd-party web fonts, there are many issues with making preload explicitly interact with rendering, so we decided to remove blocking=render from preload. See more discussions at
  • Q: This further blocks rendering on a subsequent load, which is bad for loading performance
  • A: We can't fully eliminate subsequent loading behavior, since we must use external style sheet for 3p web fonts. However, there are ways to alleviate this by starting the font loading as early as possible (see below):
    • UA can use a preload scanner that not only preloads the external style sheet
    • UA can also use a preload scanner to scan the external style sheet response to preload the font
    • The external style sheet response can also have a Link header that preloads the font
  • Q: Why making it a font-display keyword?
  • A: This provides an even stronger alternative than font-display: block. So it doesn't make much sense to be a standalone descriptor and then interact with the other font-display values. That's also the reason why its font display timeline is the same as font-display: block, though it's mainly for spec completeness -- if we ever need to use such a font while it's still pending, it's likely a misuse.
  • Q: What if it blocks rendering indefinitely?
  • A: Render-blocking stylesheets and scripts can already block rendering indefinitely (or until the UA gives up), so it's not more footgun-ish than existing render-blocking things. And it allows developers to achieve a tradeoff that's hard to achieve before.

Possible blockers

  • "CSS critical subresource" seems very under-specified at the moment (Define which subresources block the DOM load event #1088). But I guess we can just say "critical subresources should at least include font-display: critical font faces" without having to fully define what other critical subresources are.

@tabatkins @chrishtr

@jfkthame
Copy link
Contributor

This feature is supposed to be used on web fonts that are truly critical

I'm wondering exactly what it means for a web font to be "truly critical", such that it's reasonable for them to block rendering indefinitely; and if a web font is so critical to the site, why would they be loading it from a third-party server (which might be down, inaccessible, blocked, hacked, etc. at any given time)?

@Lorp
Copy link

Lorp commented May 18, 2022

Examples of truly critical webfonts:

  • fonts used for essential UI components, e.g. Google Material Symbols
  • fonts with PUA characters used by documents
  • fonts used in typeface specimens
  • fonts used in any content where users have a reasonable expectation of font fidelity (though the text might be allowed in a fallback font, the fact of the missing font needs to be obvious)

@jfkthame
Copy link
Contributor

Could such cases be handled by directly embedding the font as a data URL within the stylesheet?

@Lorp
Copy link

Lorp commented May 18, 2022

Yes that’s one way, and you could embed the stylesheet in the document of course. In normal practice AFAIK, data URL font stylesheets are typically separate from the main CSS files, so then you might need to defend against the main CSS loading but the font CSS not…

@xiaochengh
Copy link
Contributor Author

xiaochengh commented May 18, 2022

if a web font is so critical to the site, why would they be loading it from a third-party server (which might be down, inaccessible, blocked, hacked, etc. at any given time)?

I don't think this is a new issue. The web font is usually served from the same (or related) server as the font stylesheet, which is also render-blocking and third party.

Could such cases be handled by directly embedding the font as a data URL within the stylesheet?

Data url doesn't guarantee no FOIT / layout shift. For example, in Blink, data urls are handled the same was as all other urls:

  1. Run style & layout to see if the font is really used. This step may already result in a paint of the page with fallback
  2. Asynchronously decode the data url and then the font
  3. Add the font into available fonts and then re-render the page, causing issues

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-fonts] Add a font-display keyword to eliminate @font-face FOIT & layout shifts.

The full IRC log of that discussion <dbaron> Topic: [css-fonts] Add a font-display keyword to eliminate @font-face FOIT & layout shifts
<Rossen_> s/Resolution:/RESOLVED:/
<dbaron> github: https://github.com//issues/7271
<dbaron> xiaochengh: I propose adding a new keyword to font-display descriptior so it's critical and blocks load event of stylesheet.
<dbaron> xiaochengh: The purpose is to eliminate flash of invisible/unstyled text or layout shift caused by web fonts.
<dbaron> xiaochengh: There are many ways to mitigate flash or layout shift, but either complicated to use or have other issues.
<dbaron> xiaochengh: This one keyword proposal can hopefully solve this.
<dbaron> Rossen: I see a conversation back and forth between Jonathan and Lawrence on the issue. Jonathan is raising some points -- not sure they've been answered, especially his first point about what is truly critical.
<chrishtr> q+
<dbaron> s/Lawrence/Laurence/
<dbaron> s/descriptior/descriptor/
<Rossen_> q?
<Rossen_> ack chrishtr
<dbaron> chrishtr: regarding critical -- there are examples in issue of font use cases that would be considered critical. This isn't a question about why they'd be served from a 3d party domain if they were critical. If you want your site to be fast you'd ideally serve from same domain, but many sites use 3d party f ont service to serve fonts, which allows 3d party font service to update fonts over time.
<dbaron> chrishtr: xiaochengh is proposing that critical fonts should be loaded only if they're truly critical. Hope that font providers could have query parameter so that their stylesheet could say it's render blocking.
<dbaron> Rossen_: Jonathan...?
<dbaron> jfkthame: Don't have anything specific to add... was trying to understand goals and how it would work. I have a little reluctance to complicate font-display ... already fairly complex that few people understand. But I haven't tried to think through implementation issues.
<dbaron> jfkthame: ... of the new critical value.
<dbaron> jfkthame: Other question is how this relates to font loading api. Are these use cases where authors should be using font loading api to more closely cnotrol what is happening? Not sure...
<Rossen_> ack fantasai
<xiaochengh> q+
<astearns> q+
<dbaron> fantasai: My concern is that it prevents the page from showing text. I understand thatintent is that authors not use it for most of the text, but I think authors might use it for that. We normally don't make it easier to prevent the page from loading for long periods of time, perhaps forever.
<Rossen_> ack xiaochengh
<dbaron> xiaochengh: problem is developers are already trying to block render of page with various hacks. One example is to add empty external stylesheet that blocks rendering so font can load. Other is add display:none or visibility:hidden and remove when font is loaded. Since developers are already trying to do it, we can provide a better way.
<chrishtr> also, style sheets and scripts already block rendering, potentially indefintely.
<chrishtr> this attribute also indicates intent directly, and allows the UA to ignore it after a timeout
<dbaron> fantasai: I think technique of using visibility:Hidden and then visible is the developer very clearly saying that it's not to be rendered until font loads. Very clear they want invisible.
<emilio> q+
<dbaron> xiaochengh: not just making element invisible... making entire page invisible.
<dbaron> Rossen_: This is use-case specific. People can do it in a more targeted way.
<Rossen_> ack astearns
<plinss> q+
<fantasai> fantasai: my concern is that someone will be like "Oh, my wedding invitation *has* to be loaded in this font because it looks ugly otherwise, so I definitely consider this a critical font" and then the reader of the invitation, on a different connection, ends up never able to read the page
<dbaron> astearns: I think I agree with fantasai that the current hacks might be sufficient for this. But I got on queue because of concern with how this works only with style-blocking style sheets. I worry about adding something that will work in some cases but not in others. We'd have to specify what this does, if anything, if the style sheet is not render blocking. And I'm worried about adding something that has that works and doesn't work
<dbaron> astearns: characteristic.
<dbaron> xiaochengh: The intention is to make it render-blocking but after the document has already started there's no way to block render, so to keep things simple I'm just making it block load of style sheet.
<astearns> s/style-blocking/render-blocking/
<Rossen_> ack emilio
<dbaron> emilio: Similar to that... this would imply the font should load unconditionally and fully -- don't have unicode-range (presumably ignored) -- my other question isn't this more similar to how background images block the load event of the page but not of the style sheet. Doesn't achieve the rendering blocking that you want... but maybe it does? Background image loads get started before layout rather than during layout like fonts.
<chrishtr> q+
<Rossen_> ack plinss
<dbaron> Peter: I agree with fantasai. I hear the argument that authors do this so we should make it easy. That argument falls down when authors are doing something bad -- we have no obligation to do that. We should teach authors how to do fallbacks, progressive rendering ,etc.
<fantasai> +1 to "don't optimize for making the bad things easy"
<dbaron> chrishtr: Peter, I don't think there is a good way to do it right now. Only way to do it causes flashing on load. size-adjust was added but ??. This is a clean solution to this natural problem.
<dbaron> Peter: We have to weight harms between flashing and blank content. Look for other alternative rather than blocking?
<dbaron> Rossen: Not sure how this isn't creating flashing as well while you're waiting.
<dbaron> chrishtr: Shows white.. shouldn't consider that a flash of unstyled content.
<dbaron> fantasai: We already have the block keyword that shows white.
<Rossen_> q
<Rossen_> ack chrishtr
<dbaron> chrishtr: The existing keyword shows white only for the text, not the page
<dbaron> ?: ... and there's layout shift.
<dbaron> Peter: I'd say both preferable to blank page.
<dbaron> chrishtr: I think use cases for either.
<dbaron> plinss: Authors don't always consider all the factors
<dbaron> s/Peter/plinss/g
<dbaron> plinss: Doesn't mean we should make it easier... think it will lead to more abuse.
<dbaron> Rossen_: I'm hearing a good bit of feedback. So I think we should take this back to the issue and accumulate a little more consensus there before we bring it back for a resolution. Also given how many people missing today.
<fantasai> If we're adding a keyword for this, it needs to be something really obnoxious and obvious, like "block-entire-page-load-forever"
<dbaron> Rossen_: Anything else you wanted to highlight today, xiaochengh?
<dbaron> xiaochengh: The intention is not to help authors do bad things... let me outline this another way. We're trying to help authors make a tradeoff more easily... tradeoff between page stability and responsiveness. No easy way to go to one end of the tradeoff.
<dbaron> Rossen_: We'd like to move it back to the issues.
<astearns> I don’t think this is necessarily a bad thing, but I am not convinced there is no current way to achieve an appropriate result
<dbaron> fantasai: My understanding is that the proposal is to add a keyword that blocks the page rendering *literally forever* if the font doesn't load. If it's still not loading 30 seconds later because the font isn't loading, that's a problem.
<fantasai> s/problem/problem for the user/
<dbaron> plinss: I think the concern is that authors will unknowingly use this badly and wind up doing bad things by accident.
<tantek> +1 fantasai, plinss this makes it too easy for authors to do *harmful* things to users
<florian> +1 to not linking this, for the reasons said by fantasai and plinss
<emilio> one could make a case that the same can effectively already happen for any stylesheet tho
<chrishtr> Fantasai: this is not new, style sheets can and do already block rendering. I do think the spec for this should say the UA should provide a timeout.
<florian> s/linking/liking/

@astearns
Copy link
Member

On the question of indefinite blocking in the minutes above, I was interpreting this

* It has the same [Font Display Timeline](https://www.w3.org/TR/css-fonts-4/#font-display-timeline) as `font-display: block`

to mean that the load block would only apply for a short time, then be lifted (like how font-display:block will still use a fallback font after a short period elapses). Is that correct?

@xiaochengh
Copy link
Contributor Author

xiaochengh commented May 18, 2022

The load block will apply until the font is loaded.

This (setting a font display timeline) is just for technical completeness. For example, if we have a font-display: critical font in a JS-inserted (hence non-blocking) sheet , then it's possible that the UA renders the page while the font is still pending, in which case we still need a font display timeline to decide whether the fallback is visible.

@xiaochengh
Copy link
Contributor Author

xiaochengh commented May 18, 2022

@emilio: Similar to that... this would imply the font should load unconditionally and fully -- don't have unicode-range (presumably ignored) -- my other question isn't this more similar to how background images block the load event of the page but not of the style sheet. Doesn't achieve the rendering blocking that you want... but maybe it does? Background image loads get started before layout rather than during layout like fonts.

It's correct that this implies the font should load unconditionally and fully. It doesn't mean that unicode-range gets ignored -- it still affects which text the font face applies to, similar to the other descriptors for font selection.

The behavior that background images block the load event of the page but not the style sheet seem to be an unspecified behavior. We can't rely on that.

Edit: font-display: critical doesn't void segmentation. We can still segment a font family by unicode range in the same way as before, and then mark the most critical ones (as we predict) as critical. We can make the prediction based on, e.g., page language, text snippet, etc.

As an example, Google Fonts accepts a text= parameter that gives you a segmented font face for a given text snippet:

https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap&text=%E4%B8%80%E4%BA%8C%E4%B8%89

@xiaochengh
Copy link
Contributor Author

Let me summarize and respond to some major concerns raised in the meeting.

The biggest concern is that since render-blocking may cause the page rendering to be blocked infinitely (which is worse than anything else), we shouldn't add new render-blocking things.

This is the same general concern I got when specifying "render-blocking" in the HTML spec. To resolve that, UA is allowed to unblock rendering if an internal timeout is reached, even if there are still pending render-blocking resources (scripts & style sheets). See https://html.spec.whatwg.org/C/#render-blocked

So this proposal won't make the page never rendered. Nor do other render-blocking resources.


Another point is we shouldn't make it too easy for developers to do potentially bad things (e.g., page never renders). If developers are doing workarounds/hacks to achieve that (like adding/removing display: none with JS), let them be; they must be very explicit when doing potentially bad things.

There might also be concerns that putting things in the declarative syntax is the UA officially saying that this use case is legit and ok to do, whereas the JS hacks don't admit that.

First of all, making fonts render-blocking is not an inherently bad pattern, but an alternative FCP vs. CLS tradeoff that developers want to achieve. Forcing a complicated solution is a double-edged sword that, while preventing misuse of this feature, may also lead to other suboptimal workarounds and confusions.

Besides, existing JS-based workarounds (like removing display:none on FontFace.load) are not really complicated enough to prevent misusing. What is worse, such workarounds do not admit the UA-defined timeout, and would result in a strictly worse UX -- they can actually keep the page blank forever, while font-display: critical won't due to the UA-defined timeout.

Since developers already have a strong need for this, if we ignore it and pretend it's not happening, it eventually comes at the expense of the user because the UA can't do anything about something it doesn't admit. I think it's still better if we can make legit use cases easy to achieve while having a safety net (the UA-defined timeout) against misuses (and bad network), than simply banning it.

@chrishtr
Copy link
Contributor

if an internal timeout is reached

We could also strengthen the language around timeout. e.g. "the user agent should use a more strict timeout for render-blocking fonts, as the user impact of font fallback is less than a completely unstyled document".

@astearns
Copy link
Member

Since developers already have a strong need for this

Could you elaborate on why this need is “strong”? I am not sure I have seen evidence for this assertion yet.

@astearns astearns removed the Agenda+ label May 18, 2022
@xiaochengh
Copy link
Contributor Author

Since developers already have a strong need for this

To clarify, "this" means using web fonts without causing layout shifts.

It should be quite evident that developers want to achieve it but there's no easy way yet: https://www.google.com/search?q=web+font+cls

@astearns
Copy link
Member

OK, thanks for the clarification. I think things are a little fuzzier about whether developers want to block the entire page rendering until we can guarantee there will be no layout shifts from font loading.

@yisibl
Copy link
Contributor

yisibl commented May 24, 2022

@xiaochengh Can we render-blocking within a specific element via contain + font-display: critical?

@xiaochengh
Copy link
Contributor Author

I think things are a little fuzzier about whether developers want to block the entire page rendering until we can guarantee there will be no layout shifts from font loading.

Let me reiterate that it's about tradeoffs. I think the following is a reasonable tradeoff that developers want to achieve:

  • If network condition is good, then I want guaranteed 0 layout shift, while a slight rendering delay is acceptable
  • If network condition isn't so good, then I can tolerate some layout shift as long as the rendering delay isn't too big

font-display: critical ensures the first bullet. Together with the UA-defined timeout, the second bullet is also ensured.

I don't know exactly how many developers want to do that (other than this AMP example and @Lorp's previous comment), but given how widely font-display: optional has been recommended as a way to achieve a guaranteed 0 CLS but at a huge cost (page ends up in a fallback font), I think quite a number of developers currently using font-display: optional (possibly in combination with preloads) would actually prefer font-display: critical.

Can we render-blocking within a specific element via contain + font-display: critical?

That sounds like content-visibility?

@Lorp
Copy link

Lorp commented May 24, 2022

Put another way, there are times when (website) users need to know when “critical” fonts are missing. Is it haram that browsers should inform users of such failures?

@fantasai
Copy link
Collaborator

@Lorp Sounds like a use case for a missing-symbol generic font to use as the fallback, if it's so critical that you shouldn't be allowed to see the text without the specified font.

@xiaochengh Adding a timeout makes this a lot more palatable. That said I'd want the keyword to be a lot more obvious that it's introducing render blocking on the whole page, maybe something like font-display: block-page, since none of the other font-display keywords have such a global effect.

I also think @yisibl's comment about render-blocking a specific element deserves investigation. For the cases where that's desired, we should make that as easy to do as render-blocking the whole page so that authors are more likely opt to render-block just the one element instead of the whole page when render-blocking the whole page isn't necessary.

@xiaochengh
Copy link
Contributor Author

I'm fine with renaming it to font-display: block-page, with a note that it falls back to font-display: block if the UA still wants to render a frame while the font is pending (in cases like, e.g., if the timeout has been reached or if the font is in an in-body style sheet).

I think @yisibl's comment might be out of the scope of this issue, since this issue is about reducing FOIT and CLS, which are for the entire page. Maybe it should be discussed in its own issue?

@chrishtr
Copy link
Contributor

Hi, any further thoughts on this issue? I hope we can discuss it again at the next meeting this week, and I think Xiaocheng has addressed all of the concerns, especially with an improved name and advice to UAs to use a (much) shorter timeout than other resources.

@litherum
Copy link
Contributor

litherum commented Jun 15, 2022

I'm generally skeptical of this proposal. In general, it's pretty scary to add more to the web platform that intentionally makes pages load slower.

People do base64 encode font data into data: urls in stylesheets today, presumably to get the kind of behavior proposed in this issue. There are 2 problems with this existing approach:

  1. It's unwieldy for the website maintainer; they require a build step to put the font file into the CSS
  2. Base64 introduces a ~3x size blowup

What could convince me that this proposal was a good idea is evidence of at least one author saying:

  1. We use this technique today for small fonts
  2. We want to use it for big fonts
  3. But we can't because of the size blowup

@litherum
Copy link
Contributor

fonts used for essential UI components, e.g. Google Material Symbols

Icon fonts are an anti-pattern and we should not build new CSS features for them.

@jfkthame
Copy link
Contributor

fonts used for essential UI components, e.g. Google Material Symbols

Icon fonts are an anti-pattern and we should not build new CSS features for them.

In addition, I am still uneasy with the idea that such an icon font should ever block rendering of the page. Surely font-display: block is the more appropriate way to handle them.

Yes, it's not guaranteed to prevent any layout shift. That's the nature of the internet, if a page is dependent on a variety of resources that may load at different speeds (or might occasionally fail to load at all).

Developers still have the option of using the Font Loading API to manage fonts, and could use this to explicitly block rendering until certain resources are ready. So they don't need this proposal in order to achieve that outcome. It may make it easier, but I'm not sure that's desirable. As the original comment said, it will be footgun-ish. We shouldn't be making footguns more readily accessible.

@xiaochengh
Copy link
Contributor Author

@litherum

I think base64 encoding is a strictly (much) worse solution than this proposal in many aspects:

  • Deployment. base64 is much harder to deploy, as you already pointed out
  • Memory. base64 takes more space, as you also pointed out
  • Loading performance. base64 forces UA to block rendering on loading the entire font without any way out, while this proposal allows UA to unblock early if its internal timeout is hit (aka when connection is bad)

Also, here is an example where the author wants to make a big font render-blocking.

@jfkthame

To achieve the same purpose (block rendering, then unblock on font load or timeout), it will be much more complicated, and hence error-prone, with the Font Loading API. This is the common problem of polyfills, and the reason why we are speccing new features.

I already showed in my previous comments that developers have a strong (and totally legit) need for using web fonts without causing layout shifts. And in case of a strong developer need, I think we should make it easy and risk-free to use.

@astearns
Copy link
Member

astearns commented Jun 15, 2022

I am not convinced by the idea that a Font Loading API solution is inherently error-prone. A scripted solution makes it possible to encode the developer’s exact preferences. For instance, you can choose how long to wait (as requested in the linked example) where we would have to pick a single timeout that might or might not fit a particular purpose.

I would be much happier waiting for a widely-used polyfill that we could take as a much clearer sign for determining what exactly should go in to this feature.

@xiaochengh
Copy link
Contributor Author

Font Loading API polyfill actually has a worse loading performance, which is something I missed in my previous comment.

For example:

<link rel=stylesheet href="https://3p-fonts.com/cool-font.css">
<script>
document.documentElement.display = 'none';
Promise.race([
  document.fonts.load('20px cool-font'),
  setTimeoutAsPromise(1500), // in case connection is bad
]).then(() => document.documentElement.style.display = '');
</script>
<style>body { font-family: cool-font; }</style>

Then we need to wait until the font stylesheet is fully loaded and parsed to start loading the web font. This can be much slower than my proposal, which can use a preload scanner to start loading the font much earlier.

The polyfill can be improved if we also preload the font in the main document, in which case it will be as fast as my proposal. However, this isn't possible if the font URL is managed by a 3rd party provider, which is a major use case I'd like to support.

@chrishtr
Copy link
Contributor

For instance, you can choose how long to wait (as requested in the linked example) where we would have to pick a single timeout that might or might not fit a particular purpose.

How about we specify the timeout in the declaration as a required field? That would allow a custom timeout, and also make it clear in the style sheet what it's doing.

font-display: block-page 2s

font-display: block-page auto-timeout

@heycam
Copy link
Contributor

heycam commented Jun 28, 2022

The polyfill can be improved if we also preload the font in the main document, in which case it will be as fast as my proposal. However, this isn't possible if the font URL is managed by a 3rd party provider, which is a major use case I'd like to support.

By this I guess you mean that the font URL is not knowable by the page, only the style sheet URL is? And because the style sheet can't be fetched (absent CORS headers), its text can't be inserted into the document dynamically (or the font URLs extracted from inside it).

But I think the polyfill can still make it work, since it can watch for the load event of the third party style sheet:

<script>
function reveal() { document.documentElement.style.display = ""; }
document.documentElement.style.display = "none";
setTimeout(reveal, 500);
</script>
<link href="https://fonts.googleapis.com/css2?family=Smooch" rel="stylesheet" onload="document.fonts.load('20px Smooch').then(reveal);">
<style>body { font: 100px Smooch; }</style>
<p>Here is my text.</p>

@chrishtr chrishtr removed the Agenda+ label Jun 29, 2022
@chrishtr
Copy link
Contributor

I'm removing agenda+ for now while we go obtain some more evidence and details about this proposal.

@xiaochengh
Copy link
Contributor Author

@heycam I think your code snippet has the same loading performance as mine. Both have the following timeline:

main document:                              |-----------------------------|
style sheet loading (by preload scanner):      |-------|
style sheet parsed & inserted into DOM:                       *
font loading (initiated by JS):                                |-------------|
rendering unblocked:                                                          *

But the original proposal can achieve:

main document:                              |-----------------------------|
style sheet loading (by preload scanner):      |-------|
style sheet parsed & inserted into DOM:                       *
font loading (by preload scanner):               |-------------|
rendering unblocked:                                            *

Besides loading performance, I'd also like to avoid using a parser-blocking script to call document.fonts.load(), otherwise the script will be blocked on previous style sheets (which are script-blocking), which means parsing of the document will be paused until all previous sheets are loaded. Using an inline onload event handler on the style sheet seems to fix it, but AFAIK inline event handlers are strongly discouraged and even banned in some cases (reference)

aarongable pushed a commit to chromium/chromium that referenced this issue Oct 19, 2022
There's a proposal[1] to enable web fonts to block rendering, in order
to reduce CLS. There's an open question regarding how long we should
allow developers to hold off rendering for fonts (as we want to avoid
LCP and FCP regressions)

The above feature could be limited to critical & preloaded fonts, in
order to reduce that risk.

As such, we need to collect the following data:
* The time in which all the render blocking resources are loaded, and
rendering is no longer blocked.
* The time in which all preloaded fonts have arrived - this assumes that
preloading a font is a developer signal regarding its criticality.
* The maximum time between these two - as that's a good approximation of
the new FCP.
* The difference between these two - as that would tell us if holding
rendering for those fonts would be helpful at all, and how much it could
delay FCP.

This CL implements that data collection.

[1] w3c/csswg-drafts#7271

Change-Id: Id4dc36413d0ad79badb71f602a1130a833a1b216
Bug: 1372346
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3937972
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Reviewed-by: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Yoav Weiss <yoavweiss@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1061170}
blueboxd pushed a commit to blueboxd/chromium-legacy that referenced this issue Nov 30, 2022
There's a proposal[1] to enable web fonts to block rendering, in order
to reduce CLS. There's an open question regarding how long we should
allow developers to hold off rendering for fonts (as we want to avoid
LCP and FCP regressions)

The above feature could be limited to critical & preloaded fonts, in
order to reduce that risk.

As such, we need to collect the following data:
* The time in which all the render blocking resources are loaded, and
rendering is no longer blocked.
* The time in which all preloaded fonts have arrived - this assumes that
preloading a font is a developer signal regarding its criticality.
* The maximum time between these two - as that's a good approximation of
the new FCP.
* The difference between these two - as that would tell us if holding
rendering for those fonts would be helpful at all, and how much it could
delay FCP.

This CL implements that data collection.

[1] w3c/csswg-drafts#7271

(cherry picked from commit 7e5b088)

Change-Id: Id4dc36413d0ad79badb71f602a1130a833a1b216
Bug: 1372346
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3937972
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Reviewed-by: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Yoav Weiss <yoavweiss@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1061170}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3968909
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5359@{#182}
Cr-Branched-From: 27d3765-refs/heads/main@{#1058933}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests