Inter + Stack

Making Stack prettier with Inter

In this post we will walk through changing the font for the Hugo theme named Stack to the superb Inter (src) font family. Despite Stack’s website using Inter already, the default font family for Stack is still Lato—presumably to avoid breaking users’ carefully crafted Hugo sites. Which is a shame, because Inter is one of the most elegant fonts I have had the pleasure to use.

Configuration

References

On the Inter download page, it advises to configure web fonts as follows.

1
2
3
<!-- HTML in your document's head -->
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
1
2
3
4
5
6
7
8
/* CSS */
:root {
  font-family: Inter, sans-serif;
  font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */
}
@supports (font-variation-settings: normal) {
  :root { font-family: InterVariable, sans-serif; }
}

We must tailor this advice for Stack, which provides an example of how to specify a custom font for article content.

Create layouts/partials/head/custom.html under your Hugo site folder, with following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<style>
    /* Overwrite CSS variable */
    :root {
        --article-font-family: "Merriweather", var(--base-font-family);
    }
</style>

<script>
    (function () {
        const customFont = document.createElement('link');
        customFont.href = "https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap";

        customFont.type = "text/css";
        customFont.rel = "stylesheet";

        document.head.appendChild(customFont);
    }());
</script>

Applying

With this information we know enough to figure out what to change.

Create Inter and InterVariable font families

First we need an @font-face which is how we declare the font-family. Then we can use it in a font-family.

By using the CSS provided by https://rsms.me/inter/inter.css, we also consume the fonts from /inter/font-files/. If we try a curl -v https://rsms.me/inter/font-files/InterVariable.woff2?v=4.0' we can see the following Cloudflare headers in the response which confirms the font files are being served by Cloudflare’s global Content Delivery Network (CDN). This is fine for now as it should keep clients nice and speedy, however does place a dependency on Cloudflare, and rsms.me. We may want to review this if we want an entirely offline website.

1
2
3
4
< report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=[…]"}],"group":"cf-nel","max_age":604800}
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< server: cloudflare
< cf-ray: […]-LHR

So we add the following to our layouts/partials/head/custom.html which takes precedence over Stack’s custom.html, (by virtue of how Hugo Theme components precedence works) which will result in these lines being rendered in <head>[…]</head> (via the baseof.html and head.html templates). Phew! 😳

1
2
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">

Using the new font families

Now we must tell the browser to use our new font family. There is a clue in the example of how we’re meant to achieve that: --article-font-family. If we search through the Stack source we find the variables.scss. Although we could redefine the whole file, we may need to handle compiling it to CSS. Which would probably be fine, but we don’t have to! The double-hyphen indicates native CSS variables. This may be obvious to you but they didn’t exist when I first started working with CSS! So we can just set the variables we care about and we’re done.

And rather than just changing the--article-font-family, we can change the font everywhere by setting --base-font-family. Which gives us the following addition to layouts/partials/head/custom.html.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<style>
    :root {
        --base-font-family: Inter, sans-serif;
    }
    @supports (font-variation-settings: normal) {
        :root {
            --base-font-family: InterVariable, sans-serif;
        }
    }
</style>

Configuring font features

The last part to configuring Inter’s features (see below for available features). We can set all the ones we want in the same section as before, in layouts/partials/head/custom.html. We can check if it’s working by comparing the results in Verify Features with the enabled (On) section of Available Features.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<style>
    :root {
        --base-font-family: Inter, sans-serif;
        font-feature-settings: 'calt', 'dlig', 'ss02', 'ss07', 'ss08';
    }
    @supports (font-variation-settings: normal) {
        :root {
            --base-font-family: InterVariable, sans-serif;
            font-feature-settings: 'calt', 'dlig', 'ss02', 'ss07', 'ss08';
        }
    }
</style>

Remove Lato

This last step may not be strictly necessary, but doing it made sense to me.

In Stack’s footer (via custom-font.html) is some Javascript which creates a link to the Lato font from Google Fonts. We don’t need this, so probably don’t want it there. Which we can do by creating an empty file in layouts/partials/footer/components/custom-font.html.

Features

We have replicated the #features section here to check if the font configuration (font-feature-settings) is working correctly on this site. The left column have the styles forced off (0), and the right column forced on (1). When the font face is configured correctly, the left will stay as the primitive versions, and the right will show the stylized versions.

Available Features

Off On
calt
3x9  12:34  3–8  +8+x
(SEMI)PER[M]ANE{N}T
-> –> —> => ==> <->
S@N  s@n  :-)  •Smile
3x9  12:34  3–8  +8+x
(SEMI)PER[M]ANE{N}T
-> –> —> => ==> <->
S@N  s@n  :-)  •Smile
dlig
Difficult affine fjord
after affine art interface
ff ffi fft ft fi tt tf df dt ff kf kt rf
rt vf vt wf wt yf yt ¡¿What?!
Difficult affine fjord
after affine art interface
ff ffi fft ft fi tt tf df dt ff kf kt rf
rt vf vt wf wt yf yt ¡¿What?!
tnum
0.45, 0.91. +0.08
1.00; 9.44, −0.13
0:00. 1.13; ~7.12
0.45, 0.91. +0.08
1.00; 9.44, −0.13
0:00. 1.13; ~7.12
frac
1/3  5/12  0123/456789
Approximately 6/16"
1/3  5/12  0123/456789
Approximately 6/16"
case
(Hello) [World] {9000}
A@B  3 + 9 ≈ 12 * 1 → X
(Hello) [World] {9000}
A@B  3 + 9 ≈ 12 * 1 → X
ccmp
j ̃  i ̀  į ́  j ̂  i ̄
Figure A⃝ #⃞ 3⃝ ×⃞
j̃  ì  į́  ĵ  ī
Figure A⃝ #⃞ 3⃝ ×⃞
sups
ABC123abc (+)−[=]
ABC123abc (+)−[=]
subs
ABC123abc (+)−[=]
ABC123abc (+)−[=]
sinf
H2O SF6 H2SO4
H2O SF6 H2SO4
dnom
ABC1234567890
ABC1234567890
numr
ABC1234567890
ABC1234567890
zero
0123
0123
ss01
1234567890
1234567890
ss02
WP0ACO9XSI1012O9
Illegal busineß βeta
WP0ACO9XSI1012O9
Illegal busineß βeta
ss07
Hello, Mästare.!?
Hello, Mästare.!?
ss08
I’m not, uhm “smol”
I’m not, uhm “smol”
ss03
I’m not, uhm “smol”
I’m not, uhm “smol”
ss05
ABC123+→
ABC123+→
ss06
ABC123+→
ABC123+→

Verify Features

Verify
calt 3x9  12:34  3–8  +8+x
(SEMI)PER[M]ANE{N}T
-> –> —> => ==> <->
S@N  s@n  :-)  •Smile
dlig Difficult affine fjord
after affine art interface
ff ffi fft ft fi tt tf df dt ff kf kt rf
rt vf vt wf wt yf yt ¡¿What?!
ss02 WP0ACO9XSI1012O9
Illegal busineß βeta
ss07 Hello, Mästare.!?
ss08 I’m not, uhm “smol”