cssfonts

What is the purpose of the @font-face specifications given for Google fonts?


Problem: I'm trying to get a Google variable font to work (I'm okay with the non-variable ones).

I am new to the mysterious world of Google fonts, and it seems there are a lot of opinions out there on how they should be implemented.

Per suggestions around in the interwebs, if I enter this in my browser to test my <link> tab in my <head>:

https://fonts.googleapis.com/css2?family=Roboto+Flex:slnt,wdth,wght@-10..0,25..150,200..700&display=swap

and I get a bunch of these:

/* latin-ext */
@font-face {
  font-family: 'Roboto Flex';
  font-style: oblique 0deg 10deg;
  font-weight: 200 700;
  font-stretch: 25% 150%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/robotoflex/v26/NaNeepOXO_NexZs0b5Qrz. . ..woff2) format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, . . . U+1E00-1E9F;
}

I thought those were to go at the top of my .css file. But it doesn't seem to make any difference. In fact, even if I leave it out for the non-variable fonts, as long as my <link> tag checks out, they work fine.

The variable font does not. Here's my .css:

#page_header {
  font-family: "Roboto Flex", Arial;
  font-weight: 400;
  font-stretch: 150%;
}

What am I not getting?

UPDATE: Upon further examination, I have discovered, via the Inspector in Firefox, that the issue is not the font-stretch but Roboto Flex is not loading. Here is my latest <link>:

https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,200..700;1,200..700&family=Roboto+Flex:slnt,wdth,wght@-10..0,25..150,200..700&display=swap

which validates in the browser and returns:

@font-face {
  font-family: 'Roboto Flex';
  font-style: oblique 0deg 10deg;
  font-weight: 200 700;
  font-stretch: 25% 150%;
  font-display: swap;
etc.

So, as it turns out my problem is not with the font's "variableness" but with the fact that it's not loading from Google (tried in Chrome as well). The Roboto Condensed is loading and rendering just fine. No mystery, but still an issue.

Problem Solved: I found that if I used the font-variation-settings that the variable specifications worked just fine.

#page_header {
    font-family: "Roboto Flex", sans-serif;
    font-variation-settings:
    "slnt" 0,
    "wdth" 150;
    font-weight: 400;
    font-size: 1.2rem;
      . . .
}

Thus, I was able to ditch loading the Roboto Condensed separately. Final <link>:

<link href="https://fonts.googleapis.com/css2?family=Roboto+Flex:slnt,wdth,wght@-10..0,25..151,100..1000&display=swap" rel="stylesheet"> 

Solution

  • Whenever you need to load a "custom font" you need @font-face rules. The syntax is based on web-standards.

    In other words the CSS retrieved via google-fonts-API doesn't have a proprietary format/syntax and is not different from a CSS you would need to load fonts locally (from your web server).

    The main difference: the CSS is dynamic when loading from google's API. Most importantly google server will apply agent detection to deliver the most suitable font files. You can easily test this by comparing the returned CSS output in Firefox vs a Chromium/blink or a Safari/Webkit browser.

    Unfortunately, this approach has its flaws: for instance modern Opera versions (also Chromium/blink) are still detected as not supporting variable fonts.

    Wether you add a <link> element in your header or a @import rule in your CSS doesn't really matter with regards to the returned CSS (albeit the @import approach is considered to be less ideal in terms of loading speed and caching).

    https://fonts.googleapis.com/css2?family=Roboto+Flex:slnt,wdth,wght@-10..0,25..150,200..700&display=swap
    

    Is a dynamic query loading the variable font

    You could as well copy the code and paste it to your own page CSS file.
    You could also download all font files and replace the src properties accordingly. That's basically what you need to do as a web designer in Europe to be GDPR compliant (no cdn resources).

    let sliders = document.querySelectorAll('input[type=range]');
    
    sliders.forEach(slider => {
      slider.addEventListener("input", (e) => {
        let weight = +wght.value;
        let width = +wdth.value;
        let slant = +slnt.value;
        preview.style.fontVariationSettings = `"wght" ${weight}, "wdth" ${width}, "slnt" ${slant}`
      });
    })
    /* latin */
    
    @font-face {
      font-family: 'Roboto Flex';
      font-style: oblique 0deg 10deg;
      font-weight: 100 1000;
      font-stretch: 25% 151%;
      font-display: swap;
      src: url(https://fonts.gstatic.com/s/robotoflex/v26/NaPccZLOBv5T3oB7Cb4i0zu6RME.woff2) format('woff2');
      unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
    }
    
    main {
      font-family: 'Roboto Flex';
      font-size: 10vmin
    }
    <label>width: <input id="wdth" type="range" min="25" max="151" value="100" step="0.1"></label>
    <label>weight: <input id="wght" type="range" min="100" max="1000" value="400" step="0.1"></label>
    <label>slant: <input id="slnt" type="range" min="-10" max="0" value="0" step="0.1"></label>
    
    <main>
      <p id="preview">Hamburgefons</p>
    </main>

    Worth noting "Roboto Flex" provides quite a few design axes – that's why the font-face appears more complex

      font-style: oblique 0deg 10deg;
      font-weight: 100 1000;
      font-stretch: 25% 151%;
    

    Notice the properties with 2 values - specifying the possible range.

    So there is no mystery =)