Starting in Chrome 83, preloaded fonts with font-display: optional will result in no FOIT or layout shifts. See https://web.dev/preload-optional-fonts/
Lighthouse has two related audits on this:
uses-rel-preload recommends requests that should be, but currently aren't, preloaded. This is based on a Lantern simulation.
font-display simply points out fonts that don't define a font-display rule. Our docs suggest they do swap, but any value passes this audit.
To keep this audit simple, I suggest we only look at _already_ preloaded fonts. If a preloaded font is not marked optional, the audit suggests making it so to avoid shifts.
The alternative would be: basically duplicate/reuse uses-rel-preload with a focus on fonts and suggest both preloading AND optional in one go. I think this advice would be too broad, and is certainly more complex. Let's just encourage usage of optional if the developer has already decided to preload a font.
That's my pitch. Open to discussion.
A few extra thoughts:
block would also prevent most layout shifts observable in Lighthouse and also makes sense for icon-based fonts. Would we try to get them to use optional? An optional icon font is pretty useless. optional for all fonts? If we don't, then we have conflicting guidance. If we do, then why bother with a separate audit that only surfaces a subset of the items in font-display?I'm on the verge of saying a new audit isn't necessary, but I think there's room to say existing font-display is the performance guidance "choose anything but auto" and this audit is the CLS guidance "use optional when you can". Separate opportunities per-metric ringing any bells team? ;)
To keep this audit simple, I suggest we only look at already preloaded fonts. If a preloaded font is not marked optional, the audit suggests making it so to avoid shifts.
+1. I don't think we should duplicate the complicated preload logic here. We already have an audit that tells them to preload their font I like the idea of this being an extra upgrade on top you unlock :)
How do we handle other font-display values? For example block would also prevent most layout shifts observable in Lighthouse and also makes sense for icon-based fonts. Would we try to get them to use optional?
Not observable in Lighthouse because, as you know, CLS can't be simulated and is just what we observe. There's still a swap period for block fonts. On an actual mobile, 3g device the text is going to cause a shift ... although if the font is preloaded, that does mitigate the chance.
There's some work being done to detect an icon font. Maybe we can just ignore icon fonts.
An optional icon font is pretty useless.
Not in Chrome >=83, but I see your point for other browsers w/o this same optimization.
CLS can't be simulated and is just what we observe. On an actual mobile, 3g device the text is going to cause a shift ... although if the font is preloaded, that does mitigate the chance.
Not just simulation. The block period is like 3s for a single request so all but the slowest connections will avoid a layout shift. Lighthouse Slow 4G applied throttling would be hard pressed to fall into the swap period.
Not in Chrome >=83
Hang on now that I've actually read the post on it... :)
I think optional is a mistake in every mobile circumstance you need a custom font. Maybe I'm misunderstanding, but preloading a font in Chrome 83 just converts the 100ms optional block period from rendering invisible text with mistaken dimensions into a global block period where nothing will be painted at all. After 100ms, the font will never be used. In that situation an icon font font-display: optional will be useless on all but the fastest connection types.
Given this reality, the advice IMO should be more like "oh you've set a font to be optional, then you should definitely preload it, regardless of where it is in the discovery tree because Chrome does this special thing" and it's a separate audit that would hypothetically report savings on CLS if we could compute it :) Not you should set every font you preload to be optional
"Starting in Chrome 83, preloaded fonts with font-display: optional will result in no FOIT or layout shifts."
That doesn't require the font to be preloaded, does it? I thought font-display optional results in no FOIT or layout shifts always now.
I don't think this should be tied to preload.
"I think optional is a mistake in every mobile circumstance you need a custom font."
I agree. It's a mistake if you need a custom font, but should be used almost universally otherwise.
We can potentially have this audit identify icon fonts, and not propose migrating to font-display:optional in those cases.
That doesn't require the font to be preloaded, does it?
The linked article says specifically
Starting in Chrome 83, link rel="preload" and font-display: optional can be combined to remove layout jank completely
Optimizations have landed in Chrome 83 to entirely remove the first render cycle for optional fonts that are preloaded with practical experiments suggest the optional font will only be used if<link rel="preload">is used, even if the preload doesn't actually result in the request happening any earlier.
Alternatively @tdresser if you were just phrasing your insider Chrome knowledge as a question to be nicer and not actually wondering what happens like we are, then please continue to share your teachings are welcome! 😆
Hi, I'm the one who implemented the change, so feel free to ping me if you want to know about the technical details.
I think it's good idea to suggest preloading for optional fonts. Without preloading, the font will pretty much not be used unless you just refreshed the page (so that you have a warm memory cache). Besides:
document.fonts.load() probably should count as a preloadoptional font gets used, while still ensuring no layout shift. Its main purpose is to reduce breakage, so it's not an alternative of preloading, and developers shouldn't rely too much on it.And I'm not sure we should suggest setting font-display: optional for preloaded fonts, regardless of icon font or not. Setting optional means the font won't be used when the user has a cold cache and slow network. So we should never set optional on a font that's critical to the page. This includes icon font and some other cases.
Alternative thoughts:
optional for non-critical fonts. Not sure how to identify non-critical fonts, thoughoptional with a warning that this comes at a cost that the font may not be used, and hope it won't be misusedAwesome, thanks for chiming in @xiaochengh! It sounds like we should proceed as planned with your existing implementation in #11255 @lemcardenas 👍 (and perhaps add a note about allowing document.fonts.load in the future as well)
For clarity @xiaochengh, does preloading an optional font have any impact on the render cycle or prevent layout shifts? Or is it just about ensuring that the font is used?
Re-reading @housseindjirdeh's article and from your and @tdresser 's comments it sounds like the layout shifts issue specifically are avoided with all optional fonts in m83+ regardless of preload status?
For clarity @xiaochengh, does preloading an
optionalfont have any impact on the render cycle or prevent layout shifts? Or is it just about ensuring that the font is used?
It's about maximizing the chance that the font is used. This should cover cases like disk cache hit and fast network.
Unfortunately, there's no way to ensure an optional font being used. That's the cost of eliminating layout shift.
At a more technical level, font preloading (for all font-display values) does have a bit impact on the render cycle -- it slightly delays the first render cycle by no more than 50ms, so that font preloading has a better chance to finish (from disk cache, fast network, etc).
For developers, this isn't much more informative than just saying "preloading is good, do that!". So maybe let's not dump that many technical details to developers.
Re-reading @housseindjirdeh's article and from your and @tdresser 's comments it sounds like the layout shifts issue specifically are avoided with all
optionalfonts in m83+ regardless ofpreloadstatus?
Exactly.
Got it, great! Thank you so much @xiaochengh !
Wow this rabbit hole goes deep. :)
A few links I found along the way:
f-d optional fonts: [css-fonts-4] font-display: optional without relayout · Issue #4108 · w3c/csswg-draftsBoiling down webfonts and perf.. here's my take:
block behaviorswap and optional.fallback boys.If I had to characterize the diff between users of swap and optional.. Both care about peformance, and are okay with a fallback font on screen. But optional folks are okay with the fallback font remaining on page, whereas swap folks would prefer the custom webfont.
Block/swap/fallback all incur layout shifts at the some point in loading.
If they didn't chose any font-display value (aka auto), our existing font-display audit just tells devs "PICK A SIDE", which seems good. 😁
If they chose block, well... it's not my cup of tea but whatever.
If they chose optional, they should def add preload (assuming the font is actually used in the initial load)
If they chose swap, then they should def also add preload. And they should consider if they're comfortable going all the way to optional.
If they chose fallback, preloading is still valuable.
I don't see why we wouldn't recommend preload for all these cases, instead of just optional. Optional has a few special powers, but we'd have to sell people on optional to do that.
Two side notes...
One, hardly any font-display docs for optional mention the case of warm loads where the font is in disk/memory cache, but it was designed with that case in mind. Without that mentioned, I see why many folks don't really consider it.
Two, spending more time looking at all these, I'm increasingly convinced that fallback and optional are superior to block and swap. There is a 100ms difference in "text on the screen" between swap and fallback, but 100ms is nothing.
Concretely,
use-performant-font-display-values.optional-users-plz-add-preload audit is that all the optimizations that are linked up are explicitly for optional, which they already are getting. How about we rescope the new audit to all webfonts?I don't see why #11255 should only recommend using preload just for optional folks. Seems better for all webfonts. .. How about we rescope the new audit to all webfonts?
I think sites that preload all of their fonts (up to 5 or 6) end up less performant than preloading none or just a couple. I think recommending preloading everything would make things worse.
I don't see why #11255 should only recommend using preload just for optional folks. Seems better for all webfonts. .. How about we rescope the new audit to all webfonts?
I think sites that preload all of their fonts (up to 5 or 6) end up less performant than preloading none or just a couple. I think recommending preloading everything would make things worse.
Well, not every font in their CSS. Just the ones that get used during initial load, which are the ones we flag. Preloading those wouldn't make things worse.
Preloading those wouldn't make things worse.
How can we know with certainty? I've always assumed that more preloading = more contention with other possibly higher priority resources that the browser happens to request just after it sees and acts on the preload directives.
Well, not every font in their CSS. Just the ones that get used during initial load, which are the ones we flag. Preloading those wouldn't make things worse.
A blanket rule of fonts that should be preloaded could be "text rendered using webfonts that appears in the viewport during load" would be a somewhat reasonable tip. Of course there's cases where a strapline might not be as important as major headings etc. Still… if it's a non scored audit, then it's still a useful tip.
If sites are using more than 3 webfonts/weights/variants, an audit rule to advise them to reduce the number of webfonts would also probably be useful imo.
I also don't think Lighthouse should tell devs to preload all their fonts.
swap and fallback. If you're already OK with the layout shifts then why create more early network contention with fonts? It's not really holding up any perf metrics and the jank coming ~600ms later isn't a gamechanger. It's a good idea if you don't have anything else going on, but a blanket "preload all of your fonts" would be quite bad advice for sites that use a lot of fonts.Also @paulirish I just saw
3) the documented optimizations don't have much to do with preload. :/
What led you to believe this? From my observations even when the font is already at the exact same depth in the discovery tree such that you would normally never preload it, it still has the effect of the optional font actually getting used if initial parsing takes any amount of time.
https://melodic-class.glitch.me/font-preload-optional.html

If you're referring to the m83 changes having nothing to do with preload, I agree there, but at the very least they inspired the web.dev article and the work here :)
@patrickhulce and I spent an hour on voice today going through this.
There was some contention (lol) on the value of bytes. "Are preloaded font bytes of equal value to renderblocking js/css bytes?" I think yes and Patrick not so much. My POV is that preloaded font bytes will move any webfont-triggered layout shift earlier (which is good) or nullify the need for a shift entirely (also good) and these bytes also carry benefits for the aesthetic fidelity (good).
We concluded that we are on opposite sides of one key question:
✨ What is the probability that preloading a font means it makes the cut before the first render?
Secondarily, Patrick brought up the 3P Font Provider scenario (aka google fonts), which unfortunately makes this whole preloading thing VERY challenging. This requires further investigation. Perhaps we can find out what % of webfonts are from the 3rd parties (cases where the exact font URL (to preload) is unknowable).
We're going to followup on these questions separately to determine if we can broaden our font-preload recommendations.
This test illustrates the challenges of preloading Google Fonts :/
The font format referenced by Google Fonts stylesheet changes subtly based on the UA with woff to desktop and woff2 to mobile (unclear why?)
A note: The challenges of preloading with <link rel=preload> can be avoided with document.fonts.load(). We just need a font value that contains the font family name, weight and style. No need to know the actual URL.
Thanks @xiaochengh that's great to know! Perhaps the associated codelab should be updated to follow that style as well then.
@paulirish given that this work as originally described was completed, would you be comfortable leaving this closed and filing a new issue describing any followup work you wanted to see happen?
I'm going to go ahead and close this out, but if there is any follow up work that needs to be done here, please feel free to file another issue or reopen.
Most helpful comment
Hi, I'm the one who implemented the change, so feel free to ping me if you want to know about the technical details.
I think it's good idea to suggest preloading for
optionalfonts. Without preloading, the font will pretty much not be used unless you just refreshed the page (so that you have a warm memory cache). Besides:document.fonts.load()probably should count as a preloadoptionalfont gets used, while still ensuring no layout shift. Its main purpose is to reduce breakage, so it's not an alternative of preloading, and developers shouldn't rely too much on it.And I'm not sure we should suggest setting
font-display: optionalfor preloaded fonts, regardless of icon font or not. Settingoptionalmeans the font won't be used when the user has a cold cache and slow network. So we should never setoptionalon a font that's critical to the page. This includes icon font and some other cases.Alternative thoughts:
optionalfor non-critical fonts. Not sure how to identify non-critical fonts, thoughoptionalwith a warning that this comes at a cost that the font may not be used, and hope it won't be misused