Home

A guide to web typography features and best practices

Fundamentals

Font Size & Metrics

Optical Sizing

  • Optical Sizing

Text Box Adjustments

#trim #vertical-baseline #baseline

[!note] Overrides should ideally be calculated automatically by the browser. But in the meantime, until Safari’s font-size-adjust is implemented in all 3, other tools like fontaine need to be utilized.

Variable Fonts

Usage & Best Practices

Font Stretch (Width | wdth)

Absolute keyword valueNumeric value
ultra-condensed50%
extra-condensed62.5%
condensed75%
semi-condensed87.5%
normal100%
semi-expanded112.5%
expanded125%
extra-expanded150%
ultra-expanded200%

CSS Properties

  • font-optical-size
  • font-stretch
  • font-weight
  • font-variation-settings

Fixing the Inheritance Problem

September 7, 2022

Both font-feature-settings and font-variation-settings take a list of font properties. The caveat is that every property you don’t set will be set to it’s default value. This makes it hard to change one setting without unsetting the rest. But luckily CSS variables can be used to fix this problem!

In the following example the weight will be set to 100 and the width to 50%, resulting in “Hello world” being rendered in a narrow bold style:

<style>
.a {
font-variation-settings:
"wdth" 50,
"wght" 700;
}
</style>
<div class="a">Hello world</div>

But in this case “Hello world” will be rendered in a narrow regular style:

<style>
.a {
font-variation-settings: "wght" 700;
}
.b {
font-variation-settings: "wdth" 50;
}
</style>
<div class="a">
<div class="b">Hello world</div>
</div>

The reason is that class b will overwrite everything set in class a. The browser doesn’t say “the weight was set to 700 earlier, so I’ll just inherit that”. It says, “weight is not set, so I’ll use the default value of 400”.

To prevent this you can use CSS variables to keep track of each value, as they will cascade down nicely:

<style>
.a,
.b {
/* Default values */
--wght: 400;
--wdth: 100;
font-variation-settings:
"wght" var(--wght),
"wdth" var(--wdth);
}
.a {
/* Override just the "wght" */
--wght: 700;
}
.b {
/* Overwrite just the "wdth" */
--wdth: 50;
}
</style>
<div class="a">
<div class="b">Hello world</div>
</div>

Now “Hello world” will be rendered in a narrow bold style, like you’d expect. Every change in a CSS variable’s value will trickle down and be used whenever font-variation-settings gets applied.

Note that you normally don’t need to use font-feature-settings or font-variation-settings. In our example you should use font-weight and font-stretch instead of manipulating the axes directly. Most OpenType features can be set through font-variant. If you do need access to low level features (for animations, specimen sites, custom axes, etc.), using CSS variables is a good way to fix the inheritance problem.

There’s also a more verbose and beginner-friendly version of this article: Boiling eggs and fixing the variable font inheritance problem.

OpenType Features

Resources

Required Layout Features

Shorthand & CSS Properties

  • Shorthand: font-variant
  • font-variant-alternates
  • font-kerning
  • font-variant-caps
    • scmp, c2sc, pcap, c2pc, unic, titl
  • font-variant-ligatures
    • clig, liga
    • dlig
    • hlig (Medieval font thing)
    • calt
  • font-variant-numeric

Ligatures

/* Keyword values */
font-variant-ligatures: normal;
font-variant-ligatures: none;
font-variant-ligatures: common-ligatures; /* <common-lig-values> */
font-variant-ligatures: no-common-ligatures; /* <common-lig-values> */
font-variant-ligatures: discretionary-ligatures; /* <discretionary-lig-values> */
font-variant-ligatures: no-discretionary-ligatures; /* <discretionary-lig-values> */
font-variant-ligatures: historical-ligatures; /* <historical-lig-values> */
font-variant-ligatures: no-historical-ligatures; /* <historical-lig-values> */
font-variant-ligatures: contextual; /* <contextual-alt-values> */
font-variant-ligatures: no-contextual; /* <contextual-alt-values> */
/* Global values */
font-variant-ligatures: inherit;
font-variant-ligatures: initial;
font-variant-ligatures: revert;
font-variant-ligatures: revert-layer;
font-variant-ligatures: unset;

Numeric

font-variant-numeric: normal;
font-variant-numeric: ordinal;
font-variant-numeric: slashed-zero;
font-variant-numeric: lining-nums; /* <numeric-figure-values> */
font-variant-numeric: oldstyle-nums; /* <numeric-figure-values> */
font-variant-numeric: proportional-nums; /* <numeric-spacing-values> */
font-variant-numeric: tabular-nums; /* <numeric-spacing-values> */
font-variant-numeric: diagonal-fractions; /* <numeric-fraction-values> */
font-variant-numeric: stacked-fractions; /* <numeric-fraction-values> */
font-variant-numeric: oldstyle-nums stacked-fractions;
/* Global values */
font-variant-numeric: inherit;
font-variant-numeric: initial;
font-variant-numeric: revert;
font-variant-numeric: revert-layer;
font-variant-numeric: unset;

Font Loading & Performance

Font Loading Strategies

  • Font loading strategies → CSSWizardry & ZachLeat
  • font libraries by the Vue ecosystem

FOIT / FOUT

  • FOIT / FOUT

Font Caching

  • ☐ max-age??
  • ☐ immutable??
  • ☐ CF only saves it for 24 hours.
  • ☐ Does it get browser-cached, if so, for how long?

Best Practices

[!important] > Best practices for fonts (web.dev) Inlining font declarations and adjusting stylesheets may be a more effective approach.

Aftab’s notes: Inlining critical subset font for headers (for LCP/FCP) and above the fold text might work out. then later on we can use the full(latin + extended + symbols), which maybe won’t need preload.

  • ☐ Need to experiment and see if preload / prefetch / early hints are required for the second set of subset fonts

Subsetting

Strategies

  • Font subsetting → Zach Leatherman’s library.
  • Subsetting based on page’s contents
  • ⭐ --- Create subsets based on character/alphabets. Probably what I’ll end up using. Instead of alphabets though, I might need to do different ones for Headings (latin1 + a few symbols + layout features, all other categories of things in other font subsets): Font Subsetting Strategies: Content-Based vs Alphabetical — Cloud Four

Layout Features

  • What layout features can be removed, since we’re not serving content in any other language than English.
  • Remove the un-kerned set, and other required layout features for other languages.
  • Remove hinting and test.

Resources

↑The command he used.

Terminal window
pyftsubset LiterataTT.ttf
-unicodes="U+0020-007F, U+00A0-00FF, U+0100-017F, U+2000-206F, U+2070-209F, U+20A0-20CF, U+2100-214F, U+2200-22FF, U+FB00-FB4F"
-layout-features='*'
-flavor="woff2"
-output-file="LiterataTT.woff2"

Unicode Range Interchange

Character Reference

[!info]

Character(s)Unicode (range)
Basic LatinU+0020-007F
Latin-1 SupplementU+00A0-00FF
Euro signU+20AC
ApostropheU+20BC
HyphenU+2010
En dashU+2013
Em dashU+2014
Left quoteU+2018
Right quoteU+2019
Single low quoteU+201A
Left double quoteU+201C
Right double quoteU+201D
Double low quoteU+201E
BullitU+2022
EllipsisU+2026
Single left pointing angleU+2039
Single right pointing angleU+203A

Unicode Character Reference:

Subset Planning

  • ☐ Create different subsets
    • Latin
    • Latin Extended
    • etc.

Font Fallback

#cls #fallback #fout #foit

Upcoming Features

Typefaces & Selection

Guidance on Choosing a Font

Monospace Font Choices

  1. weiweihuanghuang/fragment-mono: Helvetica Monospace Coding Font (github.com)
  2. The JuliaMono Typeface
  3. Commit Mono. Neutral programming typeface.
  4. displaay/Azeret: GF font from Displaay (github.com)
  5. Twilio Sans Mono (⭐)
  • Maybe opt for sf-mono on MacOS, instead of loading twiliosansmono.

Google Fonts

Additional Notes

  • What does vertical-align do?
  • ☐ Gothic Fonts
  • ☐ Disable font-synthesis. Force use the fonts/font-weights provided

Tools

Subsetting

Font Metrics & Fallback

Font Inspection

Reading & Legibility

General Resources

Typography Collections

Articles & Guides

Reference

New Typography Features

  • New typography features in Safari

Todos & Checklist

Font Feature Settings

  • ☐ #todo --- Are “Berkeley Mono” font-feature-settings accurate???
  • ☐ #todo --- Monarcha (Monarcha-Book) font-feature-settings

Implementation Checklist

  1. Create a tiny base subset, which has latin, and other things.
  2. Use the font-feature-settings to aggressively remove unnecessary layout features
  3. Use union interchange to create a second, third subset of other features
    1. LATIN + Punctuation + Common Symbols.
    2. LATIN A + LATIN B
    3. LATIN-ext
    4. ()
    5. Symbols
    6. LATIN-ext
    7. Greek, Cyrillic (based on the typeface support)
    8. Everything else