HTML and CSS course Β· Module 11: Developer Tools
Web Fonts - Fonts Worthy of a Pharaoh
In this lesson8
Your page's headings are supposed to look like stone inscriptions. But you open it on a friend's computer and see an ordinary system typeface, because the font you chose is not on their disk. The browser can only use fonts it knows - unless you deliver them together with the page. Hieroglyphs in Ancient Egypt had their unique style. Similarly, your website can use custom fonts thanks to Web Fonts. Default system fonts are limited, but with Google Fonts and the @font-face rule, you can use thousands of different typefaces.
Google Fonts - Font Library
Google Fonts is a free library of over 1500 fonts. To use a font from Google Fonts:
Method 1: Link in HTML (simplest)
You choose a typeface on fonts.google.com, and the service gives you ready-made links to paste into <head> - first the early connections, then the stylesheet with the font:
1<head>
2 <!-- Add link to Google Fonts -->
3 <link rel="preconnect" href="https://fonts.googleapis.com">
4 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
5 <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap"
6 rel="stylesheet">
7</head>The address in the third link says what you want: the family=Cinzel typeface, weights 400 and 700, and display=swap. The link alone does not change anything on the page, though - you still have to point to the font in CSS:
1/* Use the font in CSS */
2h1 {
3 font-family: 'Cinzel', serif;
4 font-weight: 700;
5}You write the typeface name in quotes, and after a comma you give a fallback family. So the order of steps is always: preconnect, the font link, and only then font-family in CSS.
Method 2: @import in CSS
You can also load the same font straight from a CSS file with an @import rule, which must be at the very top of the stylesheet:
1/* At the beginning of the CSS file */
2@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap');
3
4body {
5 font-family: 'Cinzel', serif;
6}It works, but more slowly: the browser learns about the font only after downloading your stylesheet. That is why I recommend the <link> method.
@font-face - Custom Fonts
If you have your own font file, for example a typeface you bought, register it in your stylesheet with the @font-face rule:
1@font-face {
2 font-family: 'EgyptianFont';
3 src: url('/fonts/egyptian.woff2') format('woff2'),
4 url('/fonts/egyptian.woff') format('woff');
5 font-weight: 400;
6 font-style: normal;
7 font-display: swap;
8}
9
10h1 {
11 font-family: 'EgyptianFont', serif;
12}font-family gives the font a name to use in CSS, and src lists the files starting with the best format - the browser takes the first one it supports. A font served from your own server also does not pass visitors' IP addresses to Google, which in the EU can matter because of the GDPR.
Font Formats:
- WOFF2 - best compression, supported by modern browsers
- WOFF - broader support, slightly larger size
- TTF/OTF - traditional formats, no web compression
font-display: swap
A font from the network always arrives with a delay. The font-display property decides what the browser shows before the file has loaded:
1@font-face {
2 font-family: 'MyFont';
3 src: url('/fonts/font.woff2') format('woff2');
4 /* swap: show text with system font, replace after loading */
5 font-display: swap;
6}- swap - immediately display text in the fallback font, swap after loading
- block - hide the text briefly (usually up to about 3 s) while waiting for the font
- fallback - a very short block (about 100 ms), then about 3 s to swap, and if the font does not make it, the fallback stays
- optional - if the font does not load almost instantly, stay with the fallback
swap is the safest choice for content: the text is readable from the very first moment, and the switch of typeface is just a short blink.
Preconnect and Preload - Speeding Up Loading
When you know a font will definitely be needed, you can warn the browser with two hints in <head>:
1<head>
2 <!-- Preconnect - establish connection to server earlier -->
3 <link rel="preconnect" href="https://fonts.googleapis.com">
4 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
5
6 <!-- Preload - start downloading font as soon as possible -->
7 <link rel="preload" as="font" type="font/woff2"
8 href="/fonts/egyptian.woff2" crossorigin>
9</head>preconnect only opens the connection to the server, while preload immediately downloads a specific file. For fonts, crossorigin is needed even for files from your own server - without it, the browser will download the file twice.
Font Stack
Always define fallback fonts in case the main font does not load. The browser checks the list from the left and takes the first one available:
1body {
2 /* Order: preferred -> fallback -> generic */
3 font-family: 'Cinzel', 'Georgia', 'Times New Roman', serif;
4}General rule: always end the font stack with a generic family. The classic five are serif, sans-serif, monospace, cursive and fantasy, and newer specifications added others, such as system-ui. This ensures the browser always has a fallback font to use. A typical stack for sans-serif text is Arial, Helvetica, sans-serif, and for code 'Courier New', monospace.
Web Font Optimization
Web fonts can significantly impact page performance. Here are some optimization tips:
1. Load Only Needed Weights
Every weight you request is extra data to download, so request only the ones you actually use:
1/* BAD - loading all weights */
2@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600;700;800;900&display=swap');
3
4/* GOOD - loading only those you use */
5@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap');The page looks the same, while the browser has less to download - especially with classic fonts, where each weight is a separate file.
2. Load Only Needed Characters (Subsetting)
If the page is only in English, you do not need to load Chinese or Arabic characters:
1<!-- Load only Latin characters -->
2<link href="https://fonts.googleapis.com/css2?family=Cinzel&subset=latin&display=swap"
3 rel="stylesheet">English needs only the latin set, but letters such as the Polish Δ
, Δ or Ε belong to latin-ext. In practice, Google Fonts splits a font into subsets with unicode-range anyway, so the browser downloads only the files with characters that actually appear on the page.
3. Use Variable Fonts
Modern variable fonts allow having all weights in a single file instead of several separate ones:
1@font-face {
2 font-family: 'CinzelVariable';
3 src: url('/fonts/cinzel-variable.woff2') format('woff2');
4 font-weight: 100 900; /* Weight range */
5 font-display: swap;
6}
7
8h1 {
9 font-family: 'CinzelVariable', serif;
10 font-weight: 650; /* Any value from the range! */
11}The 100 900 range tells the browser which weights the file contains, and in your rules you can use any value in between, for example 650.
Typography - A Few Additional Properties
The font alone is not everything. Readability also depends on spacing, which you know from the lesson on accessible typography:
1p {
2 /* Letter spacing - like hieroglyphs in equal intervals */
3 letter-spacing: 0.05em;
4
5 /* Word spacing */
6 word-spacing: 0.1em;
7
8 /* Line height - text readability */
9 line-height: 1.6;
10
11 /* First line indent */
12 text-indent: 2em;
13}Spacing in em units scales together with the font, a unitless line-height works as a multiplier of its size, and text-indent indents the first line of a paragraph.
Just as hieroglyphs in ancient Egypt had their unique, recognizable style, a well-chosen web font gives your page character and professionalism. My advice: two font families per page are enough - a decorative one for headings and a readable one for body text. In the next lesson you will publish your page on the internet.
Practice
In the editor below you will compare Cinzel and Lora with a system font - check in the Network panel which files get downloaded:
Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Web Fonts - Typefaces</title>
7 <link rel="preconnect" href="https://fonts.googleapis.com">
8 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9 <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=Lora:ital,wght@0,400;0,700;1,400&display=swap"
10 rel="stylesheet">
11 <link rel="stylesheet" href="style.css">
12</head>
13<body>
14 <h1>Web Fonts in Practice</h1>
15
16 <section>
17 <h2>The Cinzel font (Google Fonts)</h2>
18 <p class="cinzel-demo">This text uses the Cinzel font -
19 an elegant typeface inspired by classical inscriptions.</p>
20 <p class="cinzel-bold">Bold version (font-weight: 700)</p>
21 </section>
22
23 <section>
24 <h2>The Lora font (Google Fonts)</h2>
25 <p class="lora-demo">This text uses the Lora font -
26 a modern serif font, ideal for longer texts.</p>
27 <p class="lora-italic">Italic version (font-style: italic)</p>
28 </section>
29
30 <section>
31 <h2>Font Stack - fallback fonts</h2>
32 <p class="stack-demo">
33 font-family: 'Cinzel', 'Georgia', 'Times New Roman', serif;
34 </p>
35 <p>If Cinzel does not load, the browser will use Georgia,
36 then Times New Roman, and finally the default serif font.</p>
37 </section>
38
39 <section>
40 <h2>Font comparison</h2>
41 <p class="font-system">System font (Georgia)</p>
42 <p class="font-cinzel">Cinzel font (Google Fonts)</p>
43 <p class="font-lora">Lora font (Google Fonts)</p>
44 </section>
45</body>
46</html>Remember: a font is the scribe's handwriting - request only what you need, and always keep a fallback typeface in case of a sandstorm.
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. How do you add a font from Google Fonts to an HTML page?
2. What does the font-display: swap property do in @font-face?
Hands-on tasks in the game
- Vertical ordering
Arrange the steps for adding a Google Fonts font to a page:
- Code editor
Add preconnect, a link to Google Fonts (Cinzel), and set font-family in CSS.
- Click in order
Arrange the correct syntax for a link element with preconnect to Google Fonts:
- Click in order
How do you correctly define font-family with fallback fonts?
- Code editor
Add font-family with the appropriate font stack to three paragraphs: serif, sans-serif, and monospace.