A guide to web typography features and best practices
Fundamentals
Font Size & Metrics
- Based on cap-size
- Deep dive CSS: font metrics, line-height and vertical-align - Vincent De Oliveira (iamvdo.me)
- Font size is useless; let’s fix it @ tonsky.me
Optical Sizing
- Optical Sizing
Text Box Adjustments
#trim #vertical-baseline #baseline
- CSS text-box-trim & text-box-edge | Can I use… Support tables for HTML5, CSS3, etc
- Deep dive --- calculating font metric overrides: Notes on calculating font metric overrides [SHARED EXTENTALLY] (google.com)
[!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
- How to use variable fonts in the real world | Clearleft
- Introduction to variable fonts on the web | Articles | web.dev
Font Stretch (Width | wdth)
| Absolute keyword value | Numeric value |
|---|---|
| ultra-condensed | 50% |
| extra-condensed | 62.5% |
| condensed | 75% |
| semi-condensed | 87.5% |
| normal | 100% |
| semi-expanded | 112.5% |
| expanded | 125% |
| extra-expanded | 150% |
| ultra-expanded | 200% |
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
- Explain layout features, etc. that are useful for subsetting.
- Almanac of OpenType Features: https://sparanoid.com/lab/opentype-features/
- Check what Opentype Font Features a typeface supports: https://wakamaifondue.com/
Required Layout Features
- ccmp: Glyph Composition/Decomposition. This feature is used to compose or decompose one or more glyphs into a single glyph or multiple glyphs. For example, this feature can be used to create ligatures or split diacritics from base glyphs 12.
- locl: Localized Forms. This feature is used to substitute glyphs with forms that are preferred or required by a specific language or locale. For example, this feature can be used to change the shape of a letter depending on the language setting 1.
- mark: Mark Positioning. This feature is used to position diacritic marks relative to base glyphs. For example, this feature can be used to adjust the placement of an accent above a letter 1.
- mkmk: Mark to Mark Positioning. This feature is used to position diacritic marks relative to other diacritic marks. For example, this feature can be used to stack multiple accents above a letter 12.
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
- ⭐ --- Best of the best article on subsetting:
- ⭐ Subsetting web fonts - Walter Ebert
- fontations/klippa at main · googlefonts/fontations (github.com)
- ⭐How to subset a variable font | Clagnut by Richard Rutter - The
layout-featuresoption specifies which OpenType layout features to include, such as kerning, ligatures, numerals and alternate characters. In this example I’m usinglayout-features='*'to include all the features available. Instead, you can also add selected features to the default set. For examplelayout-features+=onum,pnum,ss01will keep the default set of features and addonum,pnumandss01(old-style and proportional numerals, and styleset 1). The default features includecalt,clig,kernandligaamong others. See the fonttools Documentation for more info onlayout-features.
↑The command he used.
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
- Unicode Range Interchange (zachleat.com)
- Unicode Range Interchange—zachleat.com
- how-to-use-unicode-interchange
Character Reference
[!info]
Character(s) Unicode (range) Basic Latin U+0020-007F Latin-1 Supplement U+00A0-00FF Euro sign U+20AC Apostrophe U+20BC Hyphen U+2010 En dash U+2013 Em dash U+2014 Left quote U+2018 Right quote U+2019 Single low quote U+201A Left double quote U+201C Right double quote U+201D Double low quote U+201E Bullit U+2022 Ellipsis U+2026 Single left pointing angle U+2039 Single right pointing angle U+203A
Unicode Character Reference:
- List of Unicode characters - Wikipedia
- Unicode Character Ranges (jrgraphix.net)
- https://yoksel.github.io/unicode-table/
Subset Planning
- ☐ Create different subsets
- Latin
- Latin Extended
- etc.
Font Fallback
#cls #fallback #fout #foit
- John Eatmon · Reduce font-related CLS in your Astro projects with Fontaine
- pixel-point/fontpie: Get your layout shifts optimized with a CLI-generated piece of CSS (github.com)
Upcoming Features
- font-size-adjust (safari | webkit)
Typefaces & Selection
Guidance on Choosing a Font
- Font choices
- UI Fonts
- Src: How to pick a Typeface for User Interface and App Design? - Pimp my Type
- Clear distinctions → lowercase L and uppercase I.
- Open Shapes
- Little contrast
- Tip: Uppercased small font-size is hard to read.
- Src: How to pick a Typeface for User Interface and App Design? - Pimp my Type
- UI Fonts
Monospace Font Choices
- weiweihuanghuang/fragment-mono: Helvetica Monospace Coding Font (github.com)
- The JuliaMono Typeface
- Commit Mono. Neutral programming typeface.
- displaay/Azeret: GF font from Displaay (github.com)
- Twilio Sans Mono (⭐)
- Maybe opt for sf-mono on MacOS, instead of loading twiliosansmono.
Google Fonts
- List | Hermes Docs (cadens.studio) —> Generate font-face and efficiently download fonts from Google.
- Filter Google Fonts → Having opsz, etc…
Additional Notes
- What does vertical-align do?
- ☐ Gothic Fonts
- ☐ Disable font-synthesis. Force use the fonts/font-weights provided
Tools
Subsetting
- zachleat/glyphhanger: Your web font utility belt. It can subset web fonts. It can find unicode-ranges for you automatically. It makes julienne fries. (github.com)
- Munter/subfont: Command line tool to optimize your webfont loading. Aggressive subsetting based on your font use, self-hosting of Google fonts and preloading (github.com)
- fonttools/fonttools: A library to manipulate font files from Python. (github.com)
Font Metrics & Fallback
- danielroe/fontaine: Automatic font fallback based on font metrics (github.com)
- pixel-point/fontpie: Get your layout shifts optimized with a CLI-generated piece of CSS (github.com)
- Capsize (seek-oss.github.io)
Font Inspection
- Generate font css with wakamai’s fondue CLI utility: Wakamai Fondue on the command line: never write font CSS again! – Pixelambacht
- Free apps by Glyphs
- FontGoggles
- FontTableViewer
Reading & Legibility
- Design Regression
- Legible Typography Book: https://legible-typography.com/
- How and why typography affects ease of reading: https://legible-typography.com/assets/downloads/DysonMary_Legibility_2023-05-04.pdf
General Resources
Typography Collections
- Links on Typography | CSS-Tricks
- Uniwidth typefaces for interface design
- An Unhealthy Obsession with Web Fonts & Type—zachleat.com
Articles & Guides
- http://webtypography.net/toc/
- https://www.smashingmagazine.com/2022/10/typographic-hierarchies/
- State of Text Rendering
Reference
- RoelN/Font-Falsehoods: Falsehoods programmers believe about fonts (github.com)
- Boiled down: fixing the variable font inheritance problem – Pixelambacht
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
- Create a tiny base subset, which has latin, and other things.
- Use the font-feature-settings to aggressively remove unnecessary layout features
- Use union interchange to create a second, third subset of other features
- LATIN + Punctuation + Common Symbols.
- LATIN A + LATIN B
- LATIN-ext
- ()
- Symbols
- LATIN-ext
- Greek, Cyrillic (based on the typeface support)
- Everything else