├── loading ├── default-embed-noswap.html ├── default-embed.html ├── font-face-hinted-noswap.html ├── font-face.html ├── font-face-hinted.html ├── font-face-hinted-preload-noswap.html ├── font-face-preload.html └── font-face-hinted-preload.html ├── favicon.svg ├── .gitignore └── README.md /loading/default-embed-noswap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Default Embed No-Swap Test Page 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 |

This uses a google font.

21 | 22 | 23 | -------------------------------------------------------------------------------- /loading/default-embed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Default Embed Test Page 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 |

This uses a google font.

21 | 22 | 23 | -------------------------------------------------------------------------------- /favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /loading/font-face-hinted-noswap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Hinted No-Swap Embed Test Page 5 | 6 | 7 | 8 | 32 | 33 | 34 |

This uses a google font.

35 | 36 | 37 | -------------------------------------------------------------------------------- /loading/font-face.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Embed Test Page 5 | 6 | 7 | 8 | 34 | 35 | 36 |

This uses a google font.

37 | 38 | 39 | -------------------------------------------------------------------------------- /loading/font-face-hinted.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Hinted No-Swap Embed Test Page 5 | 6 | 7 | 8 | 34 | 35 | 36 |

This uses a google font.

37 | 38 | 39 | -------------------------------------------------------------------------------- /loading/font-face-hinted-preload-noswap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Hinted Preload Embed No-Swap Test Page 5 | 6 | 7 | 8 | 32 | 33 | 34 |

This uses a google font.

35 | 36 | 37 | -------------------------------------------------------------------------------- /loading/font-face-preload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Embed Test Page 5 | 6 | 7 | 8 | 34 | 35 | 36 |

This uses a google font.

37 | 38 | 39 | -------------------------------------------------------------------------------- /loading/font-face-hinted-preload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Google Fonts Font-Face Hinted Preload Embed Test Page 5 | 6 | 7 | 8 | 34 | 35 | 36 |

This uses a google font.

37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # google-fonts-testing 2 | This repo is intended for performance tests comparing Google Fonts' default embed code vs. more optimal approaches. 3 | 4 | ## Reduced Test Pages 5 | 6 | All of these test pages load the SUSE Google Font from Google's gstatic font server in a variety of ways. When fonts files are referenced directly, the slightly heavier hinted version of the fonts that are typically delivered only to Windows desktop are used, as this represents a single font format that can be served to any device. 7 | 8 | ### Font Display Swap Tests 9 | 10 | - [Default Google Fonts Embed](https://scottjehl.github.io/google-fonts-testing/loading/default-embed.html): Standard embed from Google Fonts site. 11 | - [Direct Font-Face Embed with a hinted font](https://scottjehl.github.io/google-fonts-testing/loading/font-face-hinted.html): Same test page but instead of the standard embed link, this test page places the contents of the CSS file (as it is served on Windows) inside a style element in the page. The fonts are hinted windows woff2 files, which include additional information that only windows devices use. 12 | - [Direct Font-Face Embed with a hinted font](https://scottjehl.github.io/google-fonts-testing/loading/font-face-hinted-preload.html): Same as the previous test page with a rel=preload added for the woff2 file that ends up being used in the page. 13 | 14 | ### Font-Display Default (blocking) Tests 15 | 16 | The initial test pages use `font-display: swap` because that is the current google fonts default. The following test pages are the same as the first three without using `font-display: swap`, which despite allowing test to render a little faster using fallback fonts while the custom font loads, has fallen out of favor compared to a short delay that renders text solely in a custom font. 17 | 18 | These test pages likely represent a more realistic set of use cases for how folks want fonts to load currently (without the swap). 19 | 20 | - [Default Google Fonts Embed](https://scottjehl.github.io/google-fonts-testing/loading/default-embed.html): Standard embed from Google Fonts site. 21 | - [Direct Font-Face Embed with a hinted font](https://scottjehl.github.io/google-fonts-testing/loading/font-face-hinted.html): Same test page but instead of the standard embed link, this test page places the contents of the CSS file (as it is served on Windows) inside a style element in the page. The fonts are hinted windows woff2 files, which include additional information that only windows devices use. 22 | - [Direct Font-Face Embed with a hinted font](https://scottjehl.github.io/google-fonts-testing/loading/font-face-hinted-preload.html): Same as the previous test page with a rel=preload added for the woff2 file that ends up being used in the page. 23 | 24 | 25 | ## Performance Tests and Comparison 26 | 27 | Each test page was run through WebPageTest using 6 test runs on a 4G connection speed in Chrome browser from Virginia, USA with a custom user agent string to ensure that Google serves the default embed as it would for Windows devices, to present a fair comparison. (UA: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36`) 28 | 29 | Bulk Test Run, median runs compared in a timeline: https://www.webpagetest.org/video/compare.php?tests=240830_BiDcV6_DBD%2C240830_BiDc0G_DBE%2C240830_BiDcHP_DBF%2C240830_BiDcXG_DBG%2C240830_BiDcHS_DBH%2C240830_BiDcH5_DBJ&thumbSize=100&ival=100&end=visual 30 | 31 | ### Observations: 32 | - Loading fonts with font-face is faster than the render-blocking default embed. 33 | - The greatest performance improvements show in the tests that use font-face with `font-display: swap`, as the removal of the render-blocking embed link means they can begin showing text as soon as the HTML arrives. This examples show text rendering a full second sooner than the default google embed under these conditions, and the FCP metric reports that 1 second improvement as well. Given that Google fonts currently uses `font-display: swap` as its default, this approach allows the feature to truly work as designed. 34 | - For test pages that do not use `font-display: swap`, the performance improvements of moving to `font-face` are again significant, though less so from a perceived performance perspective due to the blocking nature of browsers' default font display behavior. Still, in the `font-face` examples that do not use `font-display: swap`, Text renders visually 300ms earlier than it does for pages using the default embed, and the First Contentful Paint metric is almost a full second faster than the default embed. 35 | - In these examples, preloading does not show a significant benefit, but it's likely that it would on sites with more complicated CSS that can cause later font discovery. 36 | 37 | 38 | 39 | --------------------------------------------------------------------------------