Web Typography Checklist
Tags: html, css, typography, design
Published: 2021-02-17 18:00:46

All websites need typography, but before picking a typeface for a website, there are *a lot of* things you need to consider, questions you need to ask yourself.

This post is a collection of such questions — along with suggestions and answers, for both designers and frontend developers.

## Can You Use Websafe Or System Fonts?

The best fonts are the ones you **don't** have to download — the fonts already on your system. Also known as *websafe fonts*, these include classic typefaces like "Times", "Georgia", "Arial" and "Impact".

These "classic websafe fonts" have been (mis-)used for so many years, so they don't stand out anymore. In CSS, the *generic family names* correspond to these:

```css
font-family: serif; /* Times */
font-family: sans-serif; /* Arial / Helvetica */
font-family: monospace; /* Courier */
font-family: cursive; /* Apple Chancery (Mac), Comic Sans (Windows) */
font-family: fantasy; /* Papyrus (Mac), Impact (Windows) */
```

> **Bonus:** SNL made a [really funny sketch](https://www.youtube.com/watch?v=jVhlJNJopOQ) about *Papyrus*.

The specs also supports these types:

```css
font-family: emoji;
font-family: math;
font-family: fangsong;
```

— but there are no default font-fallbacks for any of these on either OSX or Windows.

### The New `ui-` System Fonts

```css
font-family: system-ui;
font-family: ui-serif;
font-family: ui-sans-serif;
font-family: ui-monospace;
font-family: ui-rounded;
```

The `ui-`-fonts are the default *system fonts* of an operating system.  
On Windows, only `system-ui` is currently supported, which is the "Segoe UI"-font-family. 

On OSX both `system-ui` and `ui-sans-serif` is the "SF Pro"-font, `ui-monospace` is "SF Mono", whereas the `ui-serif` is the beautiful "New York":

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ly33k2pthhzo5qi9kgqc.png)

While you're not allowed to distribute them as web-fonts, Apple provides these fonts as a [free download](https://developer.apple.com/fonts/) for your (non-Apple) system.

Both dev.to and GitHub use system fonts, meaning these sites will look slightly different on a Mac, compared with a PC.

```css
body {
  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
}
```

I prefer the simpler, new `ui-`-syntax with `system-ui`-fallback:

```css
body {
  font-family: ui-sans-serif, system-ui, sans-serif;
}
```

### Pros
System Fonts are available in **all** languages, and — especially on OSX — you get really beautiful, readable and variable fonts.

### Cons
Your website will either look like Microsoft on Windows-based browsers, or Apple on OSX-based browsers.

---

## Other Options

If you're unable to use websafe- or system fonts, you need to consider these things, before choosing a font from a free font-service, or buying a licensed font:

### Should the site support multiple languages?
If yes, pick a font that supports all of them.

### Do you need multiple weights and styles *(bold, italic etc.)?*
If yes, consider using a **variable font**, as variable fonts in general saves a **lot** of space, compared with loading multiple weights and styles. One of the most popular variable fonts, is the [Inter Font-Family](https://rsms.me/inter/), which captures that classic Swiss-based typography in a single variable font.

If you do not load different weights or styles, yet write `font-weight: 700` or `font-style: italic` in your CSS-code, the browser will create [faux bold or italic](https://alistapart.com/article/say-no-to-faux-bold/):

> *Browsers can do terrible things to type. If text is styled as bold or italic and the typeface family does not include a bold or italic font, browsers will compensate by trying to create bold and italic styles themselves. The results are an awkward mimicry of real type design.*

### Should the site work in China?
If yes, find a font you can host yourself, as Google's services are not always stable in China.

### Should the website work offline?
If you're caching you site with a *Service Worker*, you must find a font, where the licence permits the font to be downloaded to the user's device.

---

## Google Fonts

[Google Fonts](https://fonts.google.com/) is a free font-service from Google, currently with 1035 font-families. Pick the font(s) you need, and you'll be guided as to how to implement and use them.

If you're using a [Content Security Policy](https://dev.to/madsstoumann/frontend-security-content-security-policy-17dl) on your site, be sure to add the entries required for *Google Fonts.*

### Self-hosted Google Fonts
*Google Fonts* can slow down your site's performance, as it's a "high-traffic"-site. For better performance, host your Google Fonts yourself.

[Here's an excellent tool](https://google-webfonts-helper.herokuapp.com/fonts) that will help you download the correct files.

---

## Licenced Fonts

There are **many** type-foundries online (my personal favorite is [typography.com](https://www.typography.com)), and you often get top-notch quality fonts. 

Quality comes at a price, though — but your site will stand out. Many licensed fonts include typographic features such as *real* [small caps and ligatures](https://www.typography.com/fonts/hoefler-text/overview) and much more.

---

## Fallback Font

When you've picked a font that is **not** a websafe- or system-font, you need to provide a generic fallback font-family. This is the one your browser will use until the real font has downloaded.

*Example, using Google Fonts' Roboto:*
```css
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
body {
  font-family: 'Roboto', sans-serif;
}
```

Here, the generic font-family `sans-serif` is the fallback-font. Notice the `display=swap` at the end of the import-line? That will be replaced with:

```css
font-display: swap;
```

There are other [font-display-options](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display), the `swap`-option:

> ... gives the font face an extremely small block period and an infinite swap period.

You can, however, experience *Layout Shifts* when the correct font has downloaded — which results in a poorer PageSpeed Index.

This is because fonts have different x-heights (the height of the lower-case "x"), ascenders, descenders and more:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k3q2h70r1ufjuqzk5iwp.png)
 
To overcome this, you can use something called *font metric override descriptors* in CSS to change the properties of the fallback-font to match the swapped font:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9a59oqzm6at5jt2bxib.png)
 
This is currently only in *Chrome* and *Edge*, but hopefully the other browsers will catch on soon. 

Jake Archibald has made a [video about performance](https://www.youtube.com/watch?v=Z6wjUOSh9Tk), where he talks about *font metric override descriptors*.

In his example, he's able to mimic the descriptors of the fallback-font to match the replaced font:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o63kiqtp2y5pmhujyzpq.png)
 
---

## Next Steps
When you've picked your font, there are only a few more things left to consider: **line-length**, **hyphenation** and **text-direction**.

---

## Line-length and font-length units
In typography, the ideal number of characters on a line is between 60 and 70.

If a line of text is **too wide**, the reader's eyes will have a hard time focusing on the text, while if it's **too narrow**, the eyes will have to travel back too often, breaking the rhythm.

CSS provides a lot of [font-relative lengths](https://developer.mozilla.org/en-US/docs/Web/CSS/length):

- `cap` (cap-height)
- `ch` (width of the glyph '0' zero)
- `em` (calculated font-size)
- `ex` (x-height of the font)
- `ic` (measure of the "水" glyph)
- `lh` (computed value of the line-height)
- `rem` (font-size of the root element)
- `rlh` ( computed value of the root line-height)  

*Example, using ch:*
```css
.class {
  width: 60ch;
}
```

---

## Hyphenation

Browsers do not support hyphenation for **all** languages.  
If your language is supported, just add this to your CSS:

```css
.class {
  hyphens: auto;
}
```

However, languages like Japanese, Thai and Korean can have sentences that *seem* to be one long string to the untrained eye. In cases like these, where the browser cannot hyphenate correctly, it's recommended to suggest a "word-break opportunity" using the "soft hyphen": `&shy;`

Unfortunately, in most CMS-based systems, an editor **cannot** type in html-code.  
I've worked on projects, where an editor will type in the pipe character `|` for "word-break opportunities" instead:

```html
De|oxy|ribo|nuclease
```

Which at render, will be replaced with:

```html
De&shy;oxy&shy;ribo&shy;nuclease
```

For Thai, which do not use spaces between words, it can be *really* difficult:

> *Thai line breaking and word breaking, unlike western languages, is still considered an unsolved problem and is still actively tackled by many linguistics researchers. Currently there is no implementation that could perfectly break a sentence to Thai words. 
Many times, it has something to do with the context. For example, the phrase "ตากลม" can be correctly broken to "ตา","กลม" or "ตาก","ลม". Each way says totally different thing but Thai readers can still perfectly understand the intended meaning, given the context.*

In problematic cases, you can use the:
```css
.class {
  word-break: break-all;
}
```
— but the result is not pretty.

---

## Right-To-Left

When working with `[dir="rtl"]`-sites, it's recommended to use [CSS Logical Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties).

This takes some "getting-used-to" for frontend-developers, who've previously only worked with english/latin-based text.

*Before:*
```css
.class {
  text-align: left;
  padding-right: 1em;
  margin-top: 1em;
}
```

*After:*
```css
.class {
  text-align: start;
  padding-inline-end: 1em;
  margin-block-start: 1em;
}
```

Safari has some issues with some of the CSS Logical Properties, one of them being `inset-inline-end`:

```css
.class {
  inset-inline-end: 1em;
  position: absolute;
}
```

For now, you need to write a hack:

```css
@media not all and (min-resolution:.001dpcm) { @supports (-webkit-appearance:none) and (stroke-color:transparent) { 
  .class {
    right: 1em;
  }
}}
```

## Final Thoughts

There are many "experimental features" or feautures that require *vendor prefixes*, when it comes to typography. On OSX you have the popular `-webkit-font-smoothing`-property, for instance. 

For *Variable Fonts* there are a number of settings, beyond the scope of this article. 

The best place for documentation is, as always, [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts).

---

Thanks for reading!