Published at
Updated at
Reading time
This post is part of my Today I learned series in which I share all my web development learnings.

I'm not a font person. I have neither the skills nor the patience to get into font fiddling. But I do notice and appreciate a site with beautiful font combinations.

Web fonts also come with challenges, such as layout shifts and the typical performance hit to load and display them.

That's why this blog uses the most boring (but fastest) fonts possible.

html {
  /* Use whatever is available */
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica,
    Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;

This font-family declaration tells the browser to use whatever font is available on a system so that it doesn't have to download anything and can display text immediately.

But that's just my tiny blog, if you're building something polished and designed, it has been common that you had to download multiple font files — one font for bold, one for italic, one for bold-italic, and so on.

But it's 2023 and variable fonts solve the multiple-download problem.

Today I learned about relative font weights, solving a problem I've had for almost a decade. Let's have a look!

The beauty of variable fonts

Variable fonts are configurable and the font-variation-settings CSS property give you font styling super powers.

MDN Compat Data (source)
Browser support info for font-varation-settings

Variable fonts provide parameters (called axes) to tweak their rendering. Instead of downloading multiple font files for bold and italic, you download one variable font with unlimited font rendering options.

font-variation-settings: "wdth" 57, "wght" 200, "slnt" -10, "opsz" 30, "ital" 1;

The CSS Fonts Module Level 4 spec defines five registered axes matching common font requirements.

Interestingly enough, the spec recommends not to use these font variations. 😅

If you want to set this variation axisUse CSS proproperties instead
Weight (wght)font-weight
Width (wdth)font-stretch
Slant (slnt) or Italic (ital)font-style
Optical size (opsz)font-optical-sizing

That's fair (I guess) because there are matching CSS properties for these axes.

But things get exciting when we look at unusual font variations.

Custom variable font axes

In addition to the registered axes, font creators can define custom variable font axes. But how do you know what axes are defined for a variable font?

To inspect a font and discover all the visual options, Wakamai Fondue is an exceptional tool. You can drop in a font and start playing with it. Here's the Roboto variable font if you want to try it.

Wakamai Fondue interface configuring Roboto with all its custom axes.

Look at this! There are 13(!) properties to tweak Roboto. 🤯

Just recently, I discovered the wonderful Shantell comic font.

Edit me, please!
.preview {
  font-family: Shantell;
  font-variation-settings: "ital" 0.5,"INFM" 50,"BNCE" 20,"SPAC" 10;

Look at this bouncy font! I love playing with the INFM and BNCE axis and am very tempted to add it to this blog.

But coming back to Roboto; you probably didn't notice it, but there's one custom axis in there that you might wanted to use since forever!

Relative font weight — the GRAD axis

You've probably encountered the following problem before: you want to change a link's font-weight on hover, and whoops... changing its font weight will also change every character's horizontal size. Bummer.

What if there were a way to make the text bolder without changing its horizontal size?

The custom GRAD axis is doing exactly this.

The term 'grade' refers to the relative weight or density of the typeface design, but differs from traditional 'weight' in that the physical space the text occupies does not change, so changing the text grade doesn't change the overall layout of the text or elements around it.

Let's see it in action.

Doggo ipsum tungg yapper he made many woofs I am bekom fat long doggosuch treat, blep very hand that feed shibe doggo.
Bold hover styles leading to a heavy reflow.

The jumping link above, obviously, isn't great. But Roboto defines a relative weight axis to help out with this problem.

p {
  font-family: Roboto;
  font-variation-settings: 'GRAD' 0;

Doggo ipsum tungg yapper he made many woofs I am bekom fat long doggo such treat, blep very hand that feed shibe doggo.

Isn't it fancy that text can be displayed in bold without getting any bigger?

Doggo ipsum tungg yapper he made many woofs I am bekom fat long doggosuch treat, blep very hand that feed shibe doggo.

Bold styles done with relative font weight.

And relative boldness works great with buttons, too!

Disclaimer: while testing things across browsers, I discovered that desktop Safari renders Roboto and the GRAD axis so subtle that it's barely noticeable. iOS Safari seemed to work fine, though.


Now, who would have thought that custom variable font axes can ease font weight transitions?

But so cool that is — for me right now: loading an article on this blog without images usually needs less than 250KB (that's everything: HTML, CSS, JS). The Roboto variable font weighs 700KB alone. 😢 I guess, I'll pass on loading it for now.

Update: I was able to reduce Roboto's size to 58KB using font subsetting.

I'd love to see the system fonts adopt the GRAD axis. Apple's San Francisco is a variable font, but it only includes the common axes.

Nevertheless, I'm very into transitioning font weights without causing layout shifts. If you're using variable fonts, it's worth checking if it supports GRAD to add some nice hover effects!

Was this TIL post helpful?
Yes? Cool! You might want to check out Web Weekly for more quick learnings. The last edition went out 4 days ago.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles