@malchata

Faster Fonts

for

Speed Fanatics

@malchata — jeremywagner.me

I'm Jeremy!

It's me, Jeremy!

 

 

How browsers

render fonts

Host fonts

on your own server

Fonts load differently than

other resources

A quick recap of

resource loading

meet the crew

A cartoony drawing of a web server.

server

A cartoony drawing of a browser.

browser

A cartoony drawing of a page resource.

resource

witness the action

A cartoony drawing of a browser requesting a resource.

request

A cartoony drawing of a web server sending a response.

response

render blocking

in progress...

A cartoony drawing of a browser holding up a paint brush.

render

Render blocking is

all about priorities

When it comes to fonts,

browsers speculate

Font loading in pictures

A web browser loading fonts on a page, with no text visible yet.

1.89 s

Font loading in pictures

A web browser loading fonts on a page, with only heading text visible (but not body copy).

2.31 s

Font loading in pictures

A web browser after loading all fonts on a page, with all text now visible.

2.42 s

Web fonts are ripe for

performance tuning

How browsers

render fonts

Host fonts

on your own server

font-display for better

rendering control

What we often do

Host your own fonts

for performance

Fewers hosts equals

less latency

Cross-origin fonts:

A waterfall chart in Chrome dev tools showing the latency involved with cross-origin font requests.

Speed Index: 3,798

WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

Same-origin fonts:

A waterfall chart in Chrome dev tools showing reducing latency with same origin font requests.

Speed Index: 2,474 (~35% improvement)

WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

Try rel=preconnect when hosting your own fonts

just isn't doable

In HTML:

<link rel="preconnect"
      href="https://fonts.googleapis.com/"
      crossorigin>
<link rel="preconnect"
      href="https://fonts.gstatic.com/"
      crossorigin>

As an HTTP response header:

Link: <https://fonts.googleapis.com/>;
      rel=preconnect;
      crossorigin,
      <https://fonts.gstatic.com/>;
      rel=preconnect;
      crossorigin

Without rel=preconnect:

A browser trace showing increased latency for font requests without `rel=preconnect` in use.

Speed Index: 3,877

WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

With rel=preconnect:

A browser trace showing decreased latency for font requests without `rel=preconnect` in use.

Speed Index: 3,619 (~7% improvement)

WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

Friendly reminder:

Don't forget about crossorigin

rel=preconnect support:

Browser suppport matrix for rel=preconnect on caniuse.com

Browser doesn't support
rel=preconnect?

Nothing bad is going to happen!

rel=dns-prefetch

is also an option

In HTML:

<link rel="dns-prefetch"
      href="https://fonts.googleapis.com/"
      crossorigin>
<link rel="dns-prefetch"
      href="https://fonts.gstatic.com/"
      crossorigin>

As an HTTP response header:

Link: <https://fonts.googleapis.com/>;
      rel=dns-prefetch;
      crossorigin,
      <https://fonts.gstatic.com/>;
      rel=dns-prefetch;
      crossorigin

Without rel=dns-prefetch:

A browser trace showing typical DNS lookup latency for font requests without `rel=dns-prefetch` in use.
WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

With rel=dns-prefetch:

A browser trace showing decreased DNS lookup latency for font requests with `rel=dns-prefetch` in use.
WebPagetest: Slow 3G. Dulles, VA. Emulated Motorola G (Gen4)

rel=dns-prefetch support:

Browser suppport matrix for rel=dns-prefetch on caniuse.com

Hosting your own fonts

gives you control

What you regain control of:

  • Use of anything within a @font-face.
  • unicode-range.
  • font-display.
  • Subsetting.
  • Easier use of rel=preload.

Friendly reminder:

mind the licensing agreements!

Host fonts on

on your own server

font-display for better

rendering control

rel=preload for

faster font loading

“The font-display descriptor for @font-face determines how a font face is displayed, based on whether and when it is downloaded and ready to use.”
CSS Fonts Module Level 4 Specification

In other words,

font-display overrides default browser rendering strategies of web fonts.

A quick example:

@font-face {
  font-family: "Crap Sans";
  font-style: normal;
  font-weight: 400;
  src: url("../fonts/crap-sans.woff2") format("woff2"),
       url("../fonts/crap-sans.woff") format("woff");
  font-display: swap; /* <-- The good stuff */
}

font-display: auto;

Browser default behavior kicks in.

font-display: swap;

The browser displays the first locally installed font in a font-family stack, then swaps in web font after it loads.

FOIT

FOUT

Embrace the FOUT

  • Text is never blocked from being read.
  • If fonts fail to download, text won't be blocked until the FOIT timeout.
  • First meaningful paint and speed index metrics of a page can be boosted.

First Meaningful Paint (FMP) and Speed Index improvements:

font-display:FMPSpeed Index
auto3,1262,509
swap1,6452,439

Considerations with swap:

  • Don't use it for icon fonts (use font-display: block; instead).
  • Don't use icon fonts. (If that's cool.)
  • Font swapping causes layout shifting.

meowni.ca/font-style-matcher

by Monica Dinculescu

font-display: optional;

FOIT occurs for a very short time. On bad connections, the browser skips loading the font, or downloads it in the background.

Learn more about
font-display on the web:

Screenshot of CSS-Tricks `font-display` article in the browser.

css-tricks.com/font-display-masses

font-display support:

Browser suppport matrix for `font-display` on caniuse.com

Browser doesn't support
font-display?

Nothing bad is going to happen!

font-display for better

rendering control

rel=preload for

faster font loading

Save-Data and skip

unnecessary fonts

"...most resource declarations specified within JavaScript and CSS are 'hidden' from the speculative parsers and incur a performance penalty. To address this, the application can use a preload link to declaratively specify which resources the user agent must fetch early to improve page performance." Preload Specification, § A.1

In other words,

rel=preload initiates an early fetch for a resource before the browser knows it even needs it.

In HTML:

<link rel="preload"
      href="/css/fonts/firasans-regular.woff2"
      as="font"
      type="font/woff2"
      crossorigin>

As an HTTP response header:

Link: </css/fonts/firasans-regular.woff2>;
      rel=preload;
      as=font;
      type=font/woff2;
      crossorigin;
      nopush

Critical request chain
without any preloading:

A suboptimal critical request chain as audited by Lighthouse.

Critical request chain with
font and CSS preloading:

An optimized critical request chain as audited by Lighthouse.

Normal font retrieval:

A resource waterfall graph of a page with fonts downloaded in their natural order.
WebPagetest: 2G. Mumbai. Emulated Motorola G (Gen1)

Reprioritizing with rel=preload:

A resource waterfall graph of a page with fonts effectively reprioritized using `rel=preload`.
WebPagetest: 2G. Mumbai. Emulated Motorola G (Gen1)

Without rel=preload

A comparison of screenshot rolls of a page loading with fonts loading normally vs. loading via `rel=preload`.

With rel=preload

Friendly reminders:

  • Omitting the as attribute causes resources to be downloaded twice. Supply a value of font for fonts.
  • Supply the resource's content type via the type attribute so browsers don't download resources they can't use.
  • You must specify a crossorigin attribute for font resources. (Yes, even for fonts on your own server.)

A few more things:

  • Don't preload things you aren't going to use on the page! (Use rel=prefetch for that)
  • Don't preload everything and the kitchen sink!
  • If specifying rel=preload as an HTTP header, use the nopush flag to prevent unwanted server pushes. (Server push is kind of tough.)

rel=preload for

faster font loading

Save-Data and skip

unnecessary fonts

Time to

wrap it up

"The Save-Data request header field consists of one or more tokens that indicate client's preference for reduced data usage, due to high transfer costs, slow connection speeds, or other reasons." HTTP Client Hints Specification, § 3.4

In other words,

Save-Data is a header sent by clients in a "data saver" mode. Applications can deliver less resources if it is present.

Toggle data saver:

A settings screen in Chrome where a user can toggle the data saver mode, along with a readout of bytes saved.

Browser sends a Save-Data header with a value of On for every request:

Request headers for font resources shown in Chrome dev tools, with the `Save-Data` header at the bottom of the list.

Save-Data use cases:

  • Serve low resolution imagery for high-res screens.
  • Stream lower quality video.
  • Opt out of server pushes.
  • Opt out of non-essential media.
  • Opt out of "nice-to-have" web fonts.

Detect Save-Data:

<?php
$saveData = false;

if(isset($_SERVER["HTTP_SAVE_DATA"]) &&
   strtolower($_SERVER["HTTP_SAVE_DATA"]) === "on") {
  $saveData = true;
}
?>

Add a class to the html element:

<?php
if($saveData === true){
  $saveDataClass = "save-data";
} else {
  $saveDataClass = "no-save-data";
}
?>

<html class="<?php echo($saveDataClass); ?>">

Modify CSS:

h1, p {
  font-family: "Helvetica", sans-serif;
}

.no-save-data h1, .no-save-data p {
  font-family: "Optional Sans", "Helvetica", sans-serif;
}

Without:

A list of font resources in Chrome's network panel, showing all fonts downloaded when `Save-Data` is off.

With:

A list of font resources in Chrome's network panel, showing only a few fonts downloaded because `Save-Data` is on.

Without:

A page rendering with the body copy in a web font.
Fira Sans

With:

A page rendering with the body copy in a system font because `Save-Data` is on.
System sans

Learn more about
Save-Data on the web:

Screenshot of CSS-Tricks `Save-Data` article in the browser.

css-tricks.com/help-users-save-data

Save-Data and skip

unnecessary fonts

Time to

wrap it up

 

 

With thanks to:

Ben Schwarz

Ben Schwarz
@benschwarz

Karolina Szczur

Karolina Szczur
@fox

Zach Leatherman

Zach Leatherman
@zachleat

Addy Osmani

Addy Osmani
@addyosmani

Monica Dinculescu

Monica Dinculescu
@notwaldorf

Ilya Grigorik

Ilya Grigorik
@igrigorik

...and thank you!

Slide deck link:

jlwagner.net/talks/faster-fonts

A man flying through the sky on a jet pack.

End!