Most of the web is text, so typography has a huge effect on how a site feels and how easy it is to use. CSS gives you control over the typeface, size, weight, spacing and alignment of text. In this lesson you will learn the CSS fonts and text properties that matter most for readable, good-looking text.
Choosing CSS fonts with font-family
The font-family property takes a font stack: a comma-separated list of fonts. The browser uses the first one that is available on the device and falls back to the next. Always end with a generic family such as sans-serif, serif or monospace so there is always something to use.
The generic name system-ui uses the operating system’s own interface font (Segoe UI on Windows, San Francisco on Apple devices, Roboto on many Android phones). It loads instantly because nothing is downloaded, which is why many modern sites use it for body text.
Font names with spaces should be in quotes, for example "Noto Sans Tamil". Because font-family is inherited, you usually set it once on body and only change it for headings or code.
Size, weight and style
| Property | Example | What it does |
|---|---|---|
font-size | 1.125rem | How large the text is |
font-weight | 400, 700 | Thickness, from 100 (thin) to 900 (black); bold equals 700 |
font-style | italic | Italic or normal |
line-height | 1.6 | Space between lines of text |
font | italic 700 1.25rem/1.4 serif | Shorthand for several font properties |
Use rem for font sizes. 1rem equals the root font size, which is 16px by default but changes if the user has set a larger text size in their browser. Pixel font sizes ignore that preference, which hurts people with low vision. You will learn more about units in CSS Units.
For line-height, use a plain number with no unit, such as 1.5. It is multiplied by each element’s own font size, so headings and small text each get proportional spacing. Body text reads best between about 1.4 and 1.7.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A readable text setup</title>
<style>
body {
font-family: system-ui, "Segoe UI", Roboto, sans-serif;
font-size: 1.0625rem;
line-height: 1.6;
color: #1f2328;
max-width: 65ch; /* comfortable line length */
margin-inline: auto;
padding: 20px;
}
h1 {
font-family: Georgia, "Times New Roman", serif;
font-size: 2.25rem;
font-weight: 700;
line-height: 1.2;
}
.lead { font-size: 1.25rem; color: #555; }
code { font-family: ui-monospace, Consolas, monospace; background: #f2f2f2; padding: 0 4px; }
</style>
</head>
<body>
<h1>A weekend in Hampi</h1>
<p class="lead">Boulders, temples and sunsets over the Tungabhadra river.</p>
<p>Hampi was the capital of the Vijayanagara Empire. Today you can explore the ruins by bicycle, starting early to avoid the afternoon heat. Carry water and wear comfortable shoes.</p>
<p>This column is limited with <code>max-width: 65ch</code>, roughly 65 characters per line.</p>
</body>
</html>Tip: Long lines are tiring to read. Limiting text containers to around 60 to 75 characters with max-width: 65ch is one of the easiest ways to make articles feel more comfortable. The ch unit is roughly the width of the “0” character.
Aligning and decorating text
text-align:start,center,endorjustify.startandendrespect right-to-left languages, unlikeleftandright.text-decoration: add or remove underlines, for exampletext-decoration: noneon navigation links.text-underline-offsetmoves the underline away from the letters.text-transform:uppercase,lowercaseorcapitalizewithout changing the HTML.letter-spacingandword-spacing: fine-tune spacing. Small uppercase labels often look better with a little extra letter spacing.text-wrap: balance: evens out line lengths in headings so you do not get one lonely word on the last line.text-wrap: prettydoes a gentler version for paragraphs in browsers that support it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Alignment, transforms and spacing</title>
<style>
body { font-family: system-ui, sans-serif; padding: 20px; line-height: 1.5; }
.label {
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.75rem;
font-weight: 600;
color: #0b7285;
}
h2 {
text-wrap: balance;
max-width: 22ch;
}
.quote {
font-style: italic;
text-align: center;
font-size: 1.25rem;
}
a {
color: #0b5394;
text-decoration-thickness: 2px;
text-underline-offset: 4px;
}
</style>
</head>
<body>
<p class="label">Travel guide</p>
<h2>Five quiet beaches on the Konkan coast you can reach by train</h2>
<p class="quote">"Slow travel is the best travel."</p>
<p>Read the <a href="#">full itinerary</a> before you book.</p>
</body>
</html>Loading web fonts
If you need a font that is not installed on users’ devices, you can load it with the @font-face rule. You give the font a name, point to the file and then use that name in font-family. Use the compressed WOFF2 format, which every modern browser supports.
The font-display: swap descriptor tells the browser to show text in a fallback font straight away and swap to the web font once it has downloaded, so visitors are never staring at invisible text. Because the try-it editor cannot load external files, this example uses local() to look for a font already on the device:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@font-face with a fallback</title>
<style>
@font-face {
font-family: "Brand Sans";
/* on a real site: src: url("/fonts/brand-sans.woff2") format("woff2"); */
src: local("Arial");
font-weight: 400 700;
font-display: swap;
}
body {
font-family: "Brand Sans", system-ui, sans-serif;
padding: 20px;
}
.bold { font-weight: 700; }
</style>
</head>
<body>
<p>This text uses the "Brand Sans" family declared with @font-face.</p>
<p class="bold">If the font is missing, the browser falls back to system-ui.</p>
</body>
</html>Watch out: Every font file and weight is an extra download. Loading six weights of two families can slow your page noticeably. Pick one or two families, only the weights you use, and consider a variable font, which contains many weights in a single file.
When you choose fonts for scripts such as Tamil, Hindi or Malayalam, check that the font actually contains those characters. Otherwise the browser silently mixes in a fallback font for some letters and the text looks uneven.
Choosing CSS fonts well is also a design skill; see Typography for UI in the UI/UX track. Next you will learn how boxes are laid out with CSS Display and Position.
