Cover the Fonts

CDN vs Performances

We will use bad words, like UA-Sniffing, be warned

Should you self-host
Google Fonts?

Of course, y'all agree

Self-Hosting Is Good

  • Increased performances
  • Mitigation of SPoF
  • Privacy and Security concerns
  • Shared Browser Cache is a lie

Fonts are static assets
but they have their peculiarities

Back to Google Fonts

CSS Fonts vs Google Fonts

/* Your CSS */
.my-item {
    font-family: 'Montserrat', sans-serif;
/* Google Fonts CSS */
/* latin */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
Perf Issues
  • CSS loaded from
  • Fonts loaded from
  • Fonts are loaded (extra-)lately

The Mitt Romney Web Font Problem

  • FOUT vs FOIT debate
  • Google Fonts: font-display: swap; by default
  • Prefer font-display: optional to prevent layout shifts

Preload the font!

<link rel="preconnect" href="">

Hashed names: can’t preload the fonts

Google Fonts 101

  • Fonts are static assets
  • Avoid alt-domain
  • Use preconnect
  • Unpredictable names means no preload
  • Focus on readability w/ font-display stategies

What About Self-Hosting?


  • Avoid extra-CSS calls
  • Still use
    • preconnect
    • font-display

Step 1: Get the Fonts

  1. Download from Google Fonts
  2. Load to your assets dir
  3. Font declaration (keep the font-display setting 😎)
    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-weight: 400;
      font-display: optional;
      src: local('Montserrat'),
           url('fonts/montserrat.woff2') format('woff2'),
           url('fonts/montserrat.woff') format('woff');

Wait, but… What?

Loaded from Google Fonts
Loaded from main domain
Fact check: font files are really big

Google Fonts Is a Cheater 😎

@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 400;
    src: url(
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;


  1. Get separate files for latin, latin-ext, etc.
  2. Declare relevant unicode-range in @font-face


(alt) Create dedicated font-file with limited glyphs

The Dark Side

Same, but different

  • Window, Linux uses hints ; MacOS doesn’t
  • Hinted fonts heavier
  • IE 9+ - 11: WOFF / Modern browsers: WOFF2
  • WOFF larger, few features

Your Options

  1. Analyze your audience, focus on the most common
  2. Serve WOFF2/no-hints, fallback to system fonts
  3. UA-Sniffing + Backend script to generate font files
  4. Mix’em all!

  • Full font-file in the backend
  • Script detects UA, generate subset
    (format, subsets,features, etc)
  • Subset files stored in Cache
  • That’s the Google Fonts’ way
We Could Do More

#1 - Variable Fonts

  • One file to rule them all
  • Focus on reflow
  • Heavier than a single file, lighter than a whole bunch
  • Counter-productive for one style only
  • Serve regular for one variant, fallback to variable for two+

#2 - Progressive Font Enrichment

  • Sends patches over a minimal font-file
  • Increase overall quality
  • Keep OpenType features and variants
  • Not ready for production 😥

Should we preload?

What about local fonts?

  • preload means forcing download
  • we may try to detect, but with errors

The two stages alternative

  • @font-face a minimal font-file
  • Inline-it in <head>
  • Prepare an extended version
  • in two flavors: hints/no-hints
  • lazy-load the extended version with JS
if( "fonts" in document ) {
    var regular = new FontFace("Montserrat", "url(Monserrat-Regular-hint-all.woff2) format('woff2')");
    var bold = new FontFace("Montserrat", "url(Montserrat-Bold-hint-all.woff2) format('woff2')", { weight: "700" });

    Promise.all([ bold.load(), regular.load() ]).then(function(fonts) {
        fonts.forEach(function(font) {
Fonts Performance optimization is tough

Optimize in the back;
mix up in the front

Performance is a matter of

  • Frontend patterns
  • Backend tools and scripts
  • Cursors to adjust between UX, audience, and efficiency
  • Fonts is no exception
m4dz's avatar

Paranoïd Web Dino · Tech Evangelist

alwaysdata logo


Thank You!

Available under licence CC BY-SA 4.0


m4dz, CC BY-SA 4.0

Interleaf images

Courtesy of Unsplash and Pexels contributors


  • Layout icons are from Entypo+
  • Content icons are from FontAwesome


  • Cover Title: Sinzano
  • Titles: Argentoratum
  • Body: Mohave
  • Code: Fira Code


Powered by Reveal.js

Source code available at