The Five Whys of Web Font Loading Performance

A presentation at Smashing TV in June 2019 in by Zach Leatherman

Slide 1

Slide 1

WHYs THE 5 WHYs OF WEB WHYs LOADIN WHYs PERFOR WHYs

Slide 2

Slide 2

WHYs WHYs OF WEB FONT WHYs LOADING WHYs PERFORMANCE WHYs

Slide 3

Slide 3

@zachleat @zachleat.com @Web Craftsperson

Slide 4

Slide 4

@zachleat HY WHY WHY WHY W HY WHY WHY WHY W HY WHY WHY WHY W HY WHY WHY WHY W HY WHY WHY WHY W

Slide 5

Slide 5

@zachleat WHY WHY WHY WHY YWHY WHY WHY WHY WHY WHY WHY WHY WHY YWHY WHY WHY WHY WHY WHY WHY WHY WHY YWHY WHY WHY WHY WHY WHY WHY WHY WHY YWHY WHY WHY WHY WHY WHY WHY WHY WHY YWHY WHY WHY WHY WHY

Slide 6

Slide 6

Y THE 5Y OF WEB FONT Y LOADING Y PERFORMANCE Y

Slide 7

Slide 7

THE DEFAULT Wordpress Site

Slide 8

Slide 8

THE DEFAULT Wordpress Site 595 KB 35 requests

Slide 9

Slide 9

17% WEB Fonts 100 KB in 5 requests YYYYY 48% Images, 8 requests 22% JavaScript, 12 requests 17% Fonts, 5 requests 12% CSS, 8 requests 1% HTML, 2 requests

Slide 10

Slide 10

Y SANS SERIF 15.3 KB

Slide 11

Slide 11

YY SANS SERIF BOLD 15.3 KB

Slide 12

Slide 12

YYY SERIF 22.9 KB

Slide 13

Slide 13

YYYY 20.8 KB SERIF ITALIC

Slide 14

Slide 14

YYYY Y 26.2 KB SERIF BOLD

Slide 15

Slide 15

All demos on GitHub https://github.com/zachleat/performance-sometime

Slide 16

Slide 16

https://www.webpagetest.org/ METHODOLOGY 3G Network Speed HTTP/2 and HTTPS CHROME & WOFF2 ONLY FONT OPTIMIZATIONS @zachleat

Slide 17

Slide 17

THE default Wordpress Site SERIF SANS-SERIF BOLD SERIF BOLD SERIF ITALIC SANS-SERIF first render 3.3s visually complete 5.7s

Slide 18

Slide 18

OUR OPPONENTS: INVISIBLE TEXT TEXT IN MOTION

Slide 19

Slide 19

OUR OPPONENTS: INVISIBLE TEXT FOIT TEXT IN MOTION

Slide 20

Slide 20

@zachleat https://twitter.com/jmuspratt/status/561239961924403200

Slide 21

Slide 21

OUR OPPONENTS: INVISIBLE TEXT TEXT IN MOTION FOUT

Slide 22

Slide 22

CRITICAL REQUEST CHAINS DOMCONTENTLOADED FIRST CONTENTFUL PAINT FIRST PAINT PERFORMANCE METRICS FIRST RENDER VISUALLY COMPLETE SPEED INDEX ONLOAD TIME TO INTERACTIVE CPU IDLE

Slide 23

Slide 23

FIRST RENDER FIRST CONTENTFUL PAINT

Slide 24

Slide 24

FIRST MEANINGFUL PAINT Finally a metric that PROPERLY accounts for web fonts ! MEASURE using LIGHTHOUSE

Slide 25

Slide 25

OPPONENTS: INVISIBLE TEXT TEXT IN MOTION NEW METRIC: ALL TEXT VISIBLE

Slide 26

Slide 26

THE default Wordpress Site ALL TEXT VISIBLE first render 3.3s ” 4.9s visually complete 5.7s

Slide 27

Slide 27

OPPONENTS: INVISIBLE TEXT TEXT IN MOTION NEW METRIC: WEB FONT REFLOW COUNT * After first render

Slide 28

Slide 28

REFLOW COUNTER 0 @zachleat

Slide 29

Slide 29

REFLOW COUNTER 10 @zachleat

Slide 30

Slide 30

REFLOW COUNTER 21 @zachleat

Slide 31

Slide 31

REFLOW COUNTER 32 @zachleat

Slide 32

Slide 32

REFLOW COUNTER 43 @zachleat

Slide 33

Slide 33

REFLOW COUNTER 54 @zachleat

Slide 34

Slide 34

REFLOW COUNTER 65 @zachleat

Slide 35

Slide 35

RE F RE LO FLO W W RE F R L E RE FL OW FLO OW W THE default Wordpress Site first render 3.3s visually complete 5.7s

Slide 36

Slide 36

OUR METRICS: ALL TEXT VISIBLE WEB FONT REFLOW COUNT

Slide 37

Slide 37

YYYYY

Slide 38

Slide 38

YYYYY “WEB-SAFE”/SYSTEM/INSTALLED FONTS

Slide 39

Slide 39

YYYYY System fonts System Fonts: Baseline: -6% 3.1s first render 3.3s -10% 5.1s visually complete 5.7s

Slide 40

Slide 40

YYYYY System fonts No network requests INSTANT RENDERING @zachleat

Slide 41

Slide 41

@zachleat THANK YOU @zachleat @zachleat.com

Slide 42

Slide 42

@zachleat

Slide 43

Slide 43

@zachleat

Slide 44

Slide 44

BEST VIEWED @zachleat IN CHROME

Slide 45

Slide 45

@zachleat https://github.com/alrra/browser-logos

Slide 46

Slide 46

@zachleat

Slide 47

Slide 47

THE default Wordpress Site first render 3.3s visually complete 5.7s

Slide 48

Slide 48

Slide 49

Slide 49

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 50

Slide 50

YYYYY PRECONNECT

Slide 51

Slide 51

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

Slide 52

Slide 52

<!— CSS —> <link rel=’dns-prefetch’ href=’//fonts.googleapis.com’> <!— Fonts —> <link rel=’preconnect’ href=’https://fonts.gstatic.com’ crossorigin> <link rel=’alternate’ …> <link rel=’alternate’ …> <script>…</script> <script>…</script> <style>…</style> <link rel=’stylesheet’ …> <link rel=’stylesheet’ href=’ https://fonts.googleapis.com/css?family= Noto Sans:400italic,700italic,400,700| Noto Serif:400italic,700italic,400,700| Inconsolata:400,700&subset=latin,latin-ext’>

Slide 53

Slide 53

PRECONNECT ! WITHOUT CSS WITH FONTS @zachleat

Slide 54

Slide 54

Preconnect Browser SUPPORT https://caniuse.com/#feat=link-rel-preconnect

Slide 55

Slide 55

PRECONNECT: GREAT FOR CROSS-ORIGIN FONT REQUESTS @zachleat

Slide 56

Slide 56

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 57

Slide 57

YYYYY THIRD PARTY ▸ SELF HOSTING

Slide 58

Slide 58

YYYYY SELF HOSTING BASE LINE ▼ ” Self Hosting: Baseline: -6% 3.1s first render 3.3s -1% 5.6s visually complete 5.7s

Slide 59

Slide 59

WHAT HAPPENED? SUPER LONG TTFB’S NETWORK CONGESTION? BAD HTTP/2 prioritiZATION @zachleat Read more: https://blog.cloudflare.com/http-2-prioritization-with-nginx/

Slide 60

Slide 60

@font-face { src: url(notosans.woff2) format(‘woff2’); } ▼ @font-face { src: url(https://performance-sometimeassets.netlify.com/notosans.woff2) format(‘woff2’); }

Slide 61

Slide 61

YYYYY SELF HOSTING SELF HOST ▼ ” Self Hosting: Baseline: -6% 3.1s first render 3.3s -1% 5.6s visually complete 5.7s

Slide 62

Slide 62

YYYYY SELF HOSTING WITH A BIT OF SHARDING USING PRECONNECT ” Self Host & Shard: Baseline: -6% 3.1s first render 3.3s 5.7s visually complete 5.7s

Slide 63

Slide 63

***DON’T DO THIS, PROBABLY SHARDING IS AN ANTI-PATTERN ON HTTP/2 @zachleat

Slide 64

Slide 64

“ ONE PERSON’S TRASH IS ANOTHER PERSON’S -PATTERN TREASURE” ” ANTI-PATTERN

Slide 65

Slide 65

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 66

Slide 66

YYYYY FONT-DISPLAY

Slide 67

Slide 67

@font-face { font-display: swap; } Shows Fallback Font Immediately, RENDER WEB FONT WHENEVER @zachleat Learn more: https://font-display.glitch.me/

Slide 68

Slide 68

@font-face { font-display: optional; } RENDER WEB FONT ONLY IF CACHED @zachleat Learn more: https://font-display.glitch.me/

Slide 69

Slide 69

font-display Browser SUPPORT https://caniuse.com/#feat=css-font-rendering-controls

Slide 70

Slide 70

font-display Browser SUPPORT https://caniuse.com/#feat=css-font-rendering-controls

Slide 71

Slide 71

font-display: swap -ish @zachleat

Slide 72

Slide 72

@zachleat WE NO LONGER NEED JavaScript to load a WEB FONT !

Slide 73

Slide 73

WE NO LONGER NEED JavaScript to load a WEB FONT *WITH VISIBLE FALLBACK TEXT @zachleat

Slide 74

Slide 74

YYYYY SELF HOSTING WITH A BIT OF SHARDING USING PRECONNECT BASE LINE ▼ AND Font-DISPLAY ” New: Baseline: -3% 3.2s first render 3.3s 5.7s visually complete 5.7s

Slide 75

Slide 75

OUR OPPONENTS: INVISIBLE TEXT TEXT IN MOTION

Slide 76

Slide 76

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 77

Slide 77

WHY SELF HOST? @zachleat

Slide 78

Slide 78

<link href=”https:// fonts.googleapis.com/css? family=Lobster&display=swap” rel=”stylesheet”> https://www.zachleat.com/web/google-fonts-display/

Slide 79

Slide 79

” GOOGLE FONTS CDN WITH Font-DISPLAY SELF HOSTING WITH A BIT OF SHARDING USING PRECONNECT AND Font-DISPLAY “

Slide 80

Slide 80

https://csswizardry.com/2019/05/self-host-your-static-assets/ @zachleat

Slide 81

Slide 81

YYYYY PRELOAD

Slide 82

Slide 82

<link rel=”preload” href=”notosans.woff2” as=”font” type=”font/woff2” crossorigin>

Slide 83

Slide 83

PRELOAD BROWSER SUPPORT https://caniuse.com/#feat=link-rel-preload

Slide 84

Slide 84

YYYYY SELF HOSTING WITH A BIT OF SHARDING USING PRECONNECT BASE LINE ▼ AND Font-DISPLAY AND PRELOAD ” ⏰ New: 3.3s ▲ 3% 5.9s Baseline: first render 3.3s visually complete 5.7s

Slide 85

Slide 85

PRELOADING fonts FROM A DIFFERENT ORIGIN INCURS CONNECTION COSTS AT A BAD TIME ⚠ @zachleat

Slide 86

Slide 86

YYYYY SELF HOSTING WITH A BIT OF SHARDING AND Font-DISPLAY AND PRELOAD BASE LINE ▼ ” & New: Baseline: ▲ 15% 3.8s first render 3.3s -1% 5.6s visually complete 5.7s

Slide 87

Slide 87

OVERUSE OF PRELOAD WILL COST YOU in FIRST RENDER TIME ⚠ @zachleat

Slide 88

Slide 88

PRELOAD PRELOAD FIRST RENDER @zachleat

Slide 89

Slide 89

FIRST RENDER PRELOAD PRELOAD PRELOAD @zachleat

Slide 90

Slide 90

FIRST RENDER PRELOAD PRELOAD @zachleat PRELOAD

Slide 91

Slide 91

PRELOAD SOME, NOT ALL. HOW TO CHOOSE? @zachleat

Slide 92

Slide 92

LET’S GET… SUBJECTIVE

Slide 93

Slide 93

PRIORIZATION STRATEGY: USER DISRUPTION METRICS @zachleat

Slide 94

Slide 94

Y USER DISRUPTION Y Y Y Y PRIORIZATION YYYYY Y Y Y @zachleat Y

Slide 95

Slide 95

What reflows are most likely to BE THE MOST DISRUPTIVE? @zachleat

Slide 96

Slide 96

Y USER DISRUPTION Y Y Y Y PRIORIZATION YYYYY Y Y Y @zachleat Y

Slide 97

Slide 97

METRICS PRIORIZATION: PRELOAD ONE OF EACH FAMILY @zachleat YY YYY

Slide 98

Slide 98

Y METRICS PRIORIZATION: PRELOAD ONE OF EACH FAMILY Y Y YY YYY Y @zachleat ❤

Slide 99

Slide 99

ROMAN FALLBACK FAUX-BOLD FONT-SYNTHESIS ❤ BOLD ( @zachleat

Slide 100

Slide 100

FONT-SYNTHESIS FALLBACK Y @zachleat ) Y

Slide 101

Slide 101

@zachleat ) Y Y

Slide 102

Slide 102

DEAR WEB BROWSERS, CAN YOU COPY WEBKIT Please? NON-WEBKIT IT’S ME, MARGARET ❤ FONT-SYNTHESIS

Slide 103

Slide 103

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD & FONT-SYNTHESIS CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 104

Slide 104

MINI- REVIEW

Slide 105

Slide 105

OUR OPPONENTS: INVISIBLE TEXT TEXT IN MOTION

Slide 106

Slide 106

RE F RE LO FLO W W RE F R L E RE FL OW FLO OW W THE default Wordpress Site first render 3.3s visually complete 5.7s

Slide 107

Slide 107

PRELOAD EVERYTHING NO REFLOWS! FIRST * RENDER & New: Baseline: ▲ 15% 3.8s first render 3.3s -1% 5.6s visually complete 5.7s

Slide 108

Slide 108

R RE EFL FLO OW W RE FLO W PRELOAD TWO FONTS ❤ FONT-SYNTHESIS New: 3.3s Baseline: first render 3.3s -1% 5.6s visually complete 5.7s

Slide 109

Slide 109

YYYYY CSS FONT LOADING API

Slide 110

Slide 110

LOAD A WEB FONT USING JS // Remove existing @font-face blocks // Make it let font = new FontFace( “Noto Serif”, “url(notoserif.woff2) format(‘woff2’)” ); // Load it let loadedFont = await font.load(); // Render it document.fonts.add(loadedFont); Full Code at https://github.com/zachleat/performance-sometime/blob/master/css-font-loading.js

Slide 111

Slide 111

LOAD TWO WEB FONTS USING JS // Remove existing @font-face blocks // Make two let font = new FontFace(“Noto Serif”, /* … /); let fontBold = new FontFace(“Noto Serif”, / … */); // Load two let fonts = await Promise.all([ font.load(), fontBold.load() ]); // Render them at the same time!!! fonts.forEach(font => document.fonts.add(font)); Full Code at https://github.com/zachleat/performance-sometime/blob/master/css-font-loading.js

Slide 112

Slide 112

NO CHANGES TO CSS REQUIRED !

Slide 113

Slide 113

YYYYY ON ER EF LO W SELF HOSTING AND Font-DISPLAY AND PRELOAD: 2 of 5 AND SHARDING: 3 of 5 WITH PRECONNECT AND CSS FONT LOADING: 3 of 5 New: 3.3s 5.7s Baseline: first render 3.3s visually complete 5.7s

Slide 114

Slide 114

ROMAN FALLBACK FAUX-BOLD FONT-SYNTHESIS BOLD ( @zachleat

Slide 115

Slide 115

ROMAN FONT-SYNTHESIS FAUX-BOLD BOLD ( @zachleat ❤

Slide 116

Slide 116

JavaScript FONTS CAN BE FANCY: NETWORK INFORMATION API Opt out of fonts on slow connections https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API Save-Data Opt-out of fonts when the user has enabled Data Saver mode. https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/save-data/ PREFERS-REDUCED-MOTION https://webkit.org/blog/7551/responsive-design-for-motion/#using-reduce-motion-on-the-web @zachleat Opt-out of font reflows when the user has enabled Reduce Motion in accessibility preferences.

Slide 117

Slide 117

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 118

Slide 118

YYYY Y VARIABLE FONTS

Slide 119

Slide 119

YY VARIABLE FONTS

Slide 120

Slide 120

https://www.axis-praxis.org/ https://www.preusstype.com

Slide 121

Slide 121

YYYY Y 15.3KB 15.4KB 22.9KB 20.9KB 26.4KB 100.9KB

Slide 122

Slide 122

Y Y 100.0KB CompressaPRO-GX.woff2 Read more about Variable Font size comparisons: http://stuff.djr.com/gimlet-vf-size-test/

Slide 123

Slide 123

YYYYY SELF HOSTING WITH A SINGLE 115KB VARIABLE FONT BASE LINE ▼ ” New: Baseline: first render 3.3s visually complete 5.7s

Slide 124

Slide 124

YYYYY SELF HOSTING WITH A SINGLE 115KB VARIABLE FONT ” New: Baseline: first render 3.3s visually complete 5.7s

Slide 125

Slide 125

YYYYY SELF HOSTING WITH A SINGLE 115KB VARIABLE FONT W LO EF ER ON New: Baseline: first render 3.3s visually complete 5.7s

Slide 126

Slide 126

v-fonts.com Region 1 ntitled 2 ntitled 5 ntitled 8 titled 11 titled 14 titled 17 titled 20 titled 23 0 75 150 225 69.3 KB mean 54.1 KB Median 300

Slide 127

Slide 127

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 128

Slide 128

YYYYY SELF HOSTING AND Font-DISPLAY AND PRELOAD: 2 of 5 AND SHARDING: 3 of 5 WITH PRECONNECT AND CSS FONT LOADING: 3 of 5 New: 3.3s 5.7s Baseline: first render 3.3s visually complete 5.7s

Slide 129

Slide 129

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 130

Slide 130

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 131

Slide 131

OUR TOOLS: WOFF2 PRECONNECT SELF HOSTING SHARDING # FONT-DISPLAY PRELOAD CSS FONT LOADING API SUBSETTING VARIABLE FONTS

Slide 132

Slide 132

OUR OPPONENTS: INVISIBLE TEXT TEXT IN MOTION -ISH

Slide 133

Slide 133

All demos on GitHub https://github.com/zachleat/performance-sometime

Slide 134

Slide 134

@zachleat A COMPREHENSIVE GUIDE TO FONT LOADING STRATEGIES zachleat.com/web/comprehensive-webfonts/ 55 (and counting) font loading posts at zachleat.com/web/fonts/ Web Font Loading Recipes https://github.com/zachleat/web-font-loading-recipes

Slide 135

Slide 135

@zachleat INSPIRED BY

Slide 136

Slide 136

@zachleat THANK YOU @zachleat @zachleat.com