Ad – 728×90
🌱 CSS Basics

CSS Text & Fonts – Complete Typography Guide

Typography is one of the most visible aspects of web design. The fonts you choose, the sizes you set, the line height you use — these decisions define whether your website feels professional or amateurish. CSS gives you complete control over every aspect of text rendering. In this lesson you will learn every text and font property in CSS, how to load custom fonts, and the rules for readable, accessible typography.

⏱️ 22 min read 🎯 Beginner 📅 Updated 2026 👁️ Lesson 3 of 7

font-family – Choosing the Typeface

font-family sets the typeface. You provide a comma-separated list of font names — the browser uses the first one that is available on the user's device. The last item should always be a generic family (serif, sans-serif, monospace, cursive, fantasy) as a final fallback.

CSS
/* Font stack — browser tries each in order */
body {
  font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Serif font stack */
.article-body {
  font-family: Georgia, 'Times New Roman', Times, serif;
}

/* Monospace for code */
code, pre {
  font-family: 'Cascadia Code', 'Fira Code', Consolas, 'Courier New', monospace;
}

/* Multi-word font names must be quoted */
h1 { font-family: 'Open Sans', sans-serif; }

Web-Safe Fonts

Web-safe fonts are installed on virtually every device — you can use them without loading anything:

CSS – Common web-safe fonts
/* Sans-serif */
font-family: Arial, sans-serif;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-family: 'Segoe UI', sans-serif;          /* Windows system font */
font-family: -apple-system, sans-serif;       /* macOS system font */

/* Serif */
font-family: Georgia, serif;
font-family: 'Times New Roman', Times, serif;

/* Monospace */
font-family: Consolas, 'Courier New', monospace;
font-family: 'Lucida Console', monospace;

/* System font stack (recommended for performance) */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
             Roboto, Oxygen, Ubuntu, sans-serif;

Loading Google Fonts

Google Fonts provides 1,500+ free fonts. Add the <link> in your HTML <head>, then use the font name in CSS:

HTML – Loading Google Fonts
<head>
  <!-- Preconnect for performance -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

  <!-- The font itself -->
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
</head>
CSS – Using Google Fonts
body    { font-family: 'Inter', sans-serif; }
h1, h2  { font-family: 'Playfair Display', serif; }

font-size – Setting Text Size

CSS
/* Absolute — px is most predictable */
p    { font-size: 16px; }
h1   { font-size: 48px; }

/* Relative to root font size — best for accessibility */
/* (root = <html> font-size, usually 16px) */
p    { font-size: 1rem; }     /* 16px */
h1   { font-size: 3rem; }     /* 48px */
small { font-size: 0.875rem; } /* 14px */

/* Relative to parent font size */
.card p { font-size: 1.1em; }  /* 10% bigger than parent */

/* Viewport-relative — scales with screen width */
h1 { font-size: clamp(1.8rem, 5vw, 3.5rem); }
/* clamp(min, preferred, max) — responsive without media queries */

/* Named sizes (less precise, avoid in production) */
font-size: small;
font-size: medium;
font-size: large;
font-size: x-large;
💡
Use rem for font-size, clamp() for headings

Set font-size: 16px on html (or leave it default), then use rem everywhere else. This respects the user's browser font size preferences (accessibility). Use clamp() for headings to get fluid responsive type without media queries.

font-weight – Bold and Thin

CSS
/* Numeric values (100–900, increments of 100) */
font-weight: 100;   /* Thin */
font-weight: 300;   /* Light */
font-weight: 400;   /* Regular (normal) */
font-weight: 500;   /* Medium */
font-weight: 600;   /* SemiBold */
font-weight: 700;   /* Bold */
font-weight: 800;   /* ExtraBold */
font-weight: 900;   /* Black */

/* Keywords */
font-weight: normal;   /* = 400 */
font-weight: bold;     /* = 700 */
font-weight: lighter;  /* one step lighter than parent */
font-weight: bolder;   /* one step bolder than parent */

font-style and font-variant

CSS
/* Italic */
em, .italic { font-style: italic; }
cite { font-style: italic; }
/* Remove italic from something that's italic by default */
.not-italic { font-style: normal; }

/* Small caps — uppercase letters displayed at small-cap size */
.byline { font-variant: small-caps; }

/* Numeric formatting */
.price { font-variant-numeric: tabular-nums; }  /* fixed-width digits */
Ad – 336×280

line-height – Readability Spacing

line-height controls the vertical space between lines of text. It is one of the most important properties for readability.

CSS
/* Unitless number — recommended (multiplies the current font-size) */
p     { line-height: 1.6; }   /* 1.6 × 16px = 25.6px */
h1    { line-height: 1.2; }   /* headings need tighter spacing */
code  { line-height: 1.5; }

/* Fixed pixel — not recommended (doesn't scale with font-size) */
p { line-height: 24px; }

/* Em or rem */
p { line-height: 1.6em; }

/* Normal — browser default (~1.2) */
p { line-height: normal; }

/* Rule of thumb for body text */
body { line-height: 1.6; }   /* minimum for comfortable reading */

Text Alignment and Spacing

CSS – Text alignment
/* Horizontal alignment */
text-align: left;     /* default in LTR languages */
text-align: center;
text-align: right;
text-align: justify;  /* stretches lines to fill width (use with care) */
text-align: start;    /* respects text direction (LTR = left, RTL = right) */

/* Letter spacing */
letter-spacing: 0.05em;    /* slight open tracking — good for caps */
letter-spacing: 2px;       /* fixed — less flexible */
letter-spacing: normal;    /* default */

/* Word spacing */
word-spacing: 4px;
word-spacing: 0.2em;

/* Text indentation */
text-indent: 2rem;         /* indent first line, like a book paragraph */

/* Vertical alignment (for inline elements) */
vertical-align: baseline;
vertical-align: middle;
vertical-align: top;
vertical-align: sub;   /* subscript */
vertical-align: super; /* superscript */

text-decoration – Underlines, Strikethrough

CSS
/* Remove underline from links */
a { text-decoration: none; }

/* Add it back on hover */
a:hover { text-decoration: underline; }

/* Strikethrough */
.sale-price del { text-decoration: line-through; }

/* Overline */
.overlined { text-decoration: overline; }

/* Shorthand: line style color thickness */
a { text-decoration: underline dotted #1572B6 2px; }

/* Underline offset (spacing from baseline) */
a { text-underline-offset: 4px; }

/* Remove underline from subscript/superscript */
sub, sup { text-decoration: none; }

text-transform and White Space

CSS
/* Transform case in CSS (without changing HTML) */
.nav-link  { text-transform: uppercase; }
.card-title { text-transform: capitalize; }   /* Title Case */
.byline    { text-transform: lowercase; }
button     { text-transform: none; }           /* override inherited */

/* White space handling */
.code-snippet { white-space: pre; }      /* preserve whitespace and line breaks */
.no-wrap      { white-space: nowrap; }   /* prevent line breaks */
p             { white-space: normal; }   /* default — wrap at word boundaries */

/* Overflow for text — truncate long text with ellipsis */
.card-title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;   /* shows "..." when truncated */
}

/* Multi-line text clamp (limit to N lines) */
.card-desc {
  display: -webkit-box;
  -webkit-line-clamp: 3;        /* show max 3 lines */
  -webkit-box-orient: vertical;
  overflow: hidden;
}

The font Shorthand

Combine multiple font properties in one declaration:

CSS – font shorthand
/* font: style variant weight size/line-height family */
h1 { font: 700 2.5rem/1.2 'Playfair Display', serif; }
p  { font: normal 400 1rem/1.6 'Inter', sans-serif; }

/* font: size family — minimum valid shorthand */
small { font: 0.875rem sans-serif; }

📋 Summary

  • font-family — provide a stack of fonts + generic fallback. Load custom fonts via Google Fonts or @font-face.
  • font-size — use rem for accessibility. clamp() for fluid headings.
  • font-weight — 100–900 numeric or bold/normal keywords.
  • line-height — unitless number (1.5–1.7 for body text, 1.1–1.3 for headings).
  • text-align — left, center, right, justify.
  • letter-spacing — use em units; positive value opens tracking (good for caps).
  • text-decoration — control underlines, strikethrough, color, and offset.
  • text-transform — uppercase, capitalize, lowercase without touching HTML.
  • text-overflow: ellipsis — truncate overflowing text with "…"

Frequently Asked Questions

What is the ideal font-size for body text? +

The standard is 16px (1rem) for desktop body text — this is the browser default and is well-researched for readability. On mobile, 15–16px is ideal. Anything below 14px is problematic for readability and accessibility. For long-form articles, 17–18px can actually improve reading comfort on large screens. Never go below 14px for body text.

What is the best line-height for readability? +

For body text: 1.5–1.7 (unitless). For headings: 1.1–1.3. For compact UI labels: 1.2–1.4. The unitless form is preferred because it scales proportionally when the font-size changes. The W3C accessibility guidelines recommend a line-height of at least 1.5 for body text.

Should I use Google Fonts or system fonts? +

For performance: system fonts are faster — no extra network request. The system font stack (-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif) looks native and loads instantly. For design: Google Fonts give you better aesthetic control and brand consistency. If you use Google Fonts, always add display=swap to the URL and <link rel="preconnect"> tags to minimize load impact.

How do I add a custom font that is not on Google Fonts? +

Use @font-face to load a font file you host yourself:

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2'),
       url('/fonts/myfont.woff')  format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;  /* show fallback while loading */
}

body { font-family: 'MyFont', sans-serif; }

Always provide woff2 (best compression, all modern browsers) and woff as fallback.