MarzleyTech Learn

Home / Learn / CSS / Fonts and text styling

Fonts and text styling

Most of a website is text, so good typography is the fastest way to make a page look professional. This lesson covers every text property you'll use daily.

font-family and font stacks

font-family lists fonts in order of preference. The browser uses the first one it has.

CSS
body { font-family: "Inter", "Segoe UI", Roboto, Arial, sans-serif; }
code { font-family: "Fira Code", Consolas, monospace; }

Always end with a generic family: sans-serif, serif or monospace. The fastest choice is the system font stack, which uses the phone's own font and downloads nothing:

CSS
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }

Size, weight, style and line height

HTML · runs live in the interactive lesson
<style>
  body { font-family: system-ui, sans-serif; }
  h1 { font-size: 2rem; font-weight: 800; line-height: 1.2; }
  p { font-size: 1.05rem; line-height: 1.6; max-width: 60ch; }
  .light { font-weight: 300; }
  .italic { font-style: italic; }
</style>
<h1>Fresh mangoes from Makueni</h1>
<p>Sweet, juicy and picked this week. We deliver across Nairobi every Tuesday and Friday. Order on WhatsApp and pay with M-Pesa when the fruit arrives.</p>
<p class="light">A light weight (300).</p>
<p class="italic">An italic style.</p>
PropertyCommon valuesTip
font-size16px, 1rem, 1.25remUse rem so text respects the user's settings
font-weight400 normal, 600 semibold, 700 boldOnly use weights the font has
font-stylenormal, italic
line-height1.5, 1.6 (no unit)1.5–1.7 for body text is easiest to read
max-width on text60ch50–75 characters per line reads best

Alignment, decoration and case

HTML · runs live in the interactive lesson
<style>
  .center { text-align: center; }
  .upper { text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.8rem; color: #955a06; font-weight: 700; }
  a { color: #2563eb; text-decoration: underline; text-underline-offset: 3px; }
  .no-line { text-decoration: none; }
  .strike { text-decoration: line-through; color: #64748b; }
  .indent { text-indent: 2em; }
</style>
<p class="upper">Our services</p>
<h2 class="center">Websites that bring customers</h2>
<p><a href="#">A normal underlined link</a> and <a class="no-line" href="#">one without a line</a>.</p>
<p>Was <span class="strike">KSh 30,000</span>, now KSh 25,000.</p>
<p class="indent">This paragraph starts with an indent, like a book.</p>

Web fonts (Google Fonts)

To use a font the visitor may not have, load it. From fonts.google.com you get a line like:

HTML
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap" rel="stylesheet">

then:

CSS
body { font-family: "Poppins", sans-serif; }

Tips for speed:

  • Load only the weights you use (e.g. 400 and 700).
  • Keep display=swap so text shows immediately in a backup font.
  • One font family is usually enough; two at most (one for headings, one for body).

Text shadow and overflow

HTML · runs live in the interactive lesson
<style>
  .hero { background: #0b1b35; color: #fff; padding: 20px; font-size: 1.8rem; text-shadow: 0 2px 8px rgba(0,0,0,.5); }
  .cut { width: 220px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border: 1px solid #ccc; padding: 6px; }
</style>
<div class="hero">Technology for real solutions</div>
<p class="cut">This very long product name will be cut with three dots at the end</p>

A good typography starter

CSS
html { font-size: 100%; }             /* respect the user's setting (usually 16px) */
body { font-family: system-ui, sans-serif; line-height: 1.6; color: #1e293b; }
h1, h2, h3 { line-height: 1.2; color: #0b1b35; }
h1 { font-size: clamp(1.8rem, 5vw, 3rem); }
p { max-width: 65ch; }

clamp(min, preferred, max) makes the heading grow with the screen but never smaller than 1.8rem or larger than 3rem.

Why typography matters

About 90% of most websites is text. Good typography makes a site feel trustworthy, readable on cheap phones in sunlight, and accessible to older visitors and people with low vision. Bad typography (tiny grey text, long lines, too many fonts) makes visitors leave even when the content is good. Designers, front-end developers, bloggers and anyone building a business site use these properties daily.

Readability rules that work

RuleValueWhy
Body text size16px to 18px (1rem to 1.125rem)Smaller is hard to read on phones
Line height1.5 to 1.7 for paragraphs; 1.1 to 1.3 for headingsGives the eye room to find the next line
Line length45 to 75 characters (max-width: 65ch)Long lines are tiring; short lines feel choppy
ContrastAt least 4.5:1 for body textRequired for accessibility (WCAG AA)
Fonts per siteOne or two familiesMore looks messy and loads slowly
Paragraph spacingmargin-bottom: 1em or moreSeparates ideas clearly

Fluid type with clamp()

clamp(min, preferred, max) lets headings grow smoothly with the screen without media queries:

HTML · runs live in the interactive lesson
<style>
  body { font-family: system-ui, sans-serif; margin: 16px; }
  h1 { font-size: clamp(1.6rem, 1rem + 3vw, 3rem); line-height: 1.15; margin: 0 0 .4em; }
  h2 { font-size: clamp(1.25rem, 1rem + 1.5vw, 2rem); line-height: 1.2; }
  p  { font-size: clamp(1rem, .95rem + .25vw, 1.125rem); line-height: 1.65; max-width: 65ch; color: #1f2937; }
</style>
<h1>Websites that bring customers</h1>
<h2>Fast, mobile-friendly and easy to update</h2>
<p>Resize the preview: the heading grows on wide screens and shrinks on phones, but never below 1.6rem or above 3rem. The paragraph keeps a comfortable line length thanks to max-width in ch units.</p>

A type scale

Pick sizes from a consistent scale (each step about 1.25× the last) instead of random numbers:

HTML · runs live in the interactive lesson
<style>
  :root { --step-0: 1rem; --step-1: 1.25rem; --step-2: 1.563rem; --step-3: 1.953rem; --step-4: 2.441rem; }
  body { font-family: Georgia, serif; margin: 16px; }
  .s4 { font-size: var(--step-4); } .s3 { font-size: var(--step-3); } .s2 { font-size: var(--step-2); }
  .s1 { font-size: var(--step-1); } .s0 { font-size: var(--step-0); }
  div { margin: 4px 0; }
</style>
<div class="s4">Step 4: page title</div>
<div class="s3">Step 3: section heading</div>
<div class="s2">Step 2: card title</div>
<div class="s1">Step 1: lead paragraph</div>
<div class="s0">Step 0: body text</div>

Storing sizes in CSS variables means one change updates the whole site.

Loading web fonts quickly

Fonts are files that must download. Slow font loading causes invisible text or a jump in layout.

  • Use only the weights you need (for example 400 and 700), not all nine.
  • Add font-display: swap so text shows immediately in a fallback font.
  • Self-host fonts (download the .woff2 files) for speed and privacy, or preconnect to the font server.
  • Choose a fallback font with similar size to reduce layout shift.
  • Consider system fonts (system-ui): zero download, and they look native on every device.
CSS
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
body { font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }

Pairing fonts

PairingFeelGood for
One sans-serif in two weightsClean, modernTech companies, apps, most business sites
Serif headings + sans-serif bodyClassic and friendlyLaw firms, schools, blogs, hotels
Sans-serif headings + serif bodyEditorialMagazines, long articles
Monospace for code onlyTechnicalDocumentation, tutorials

Avoid decorative or script fonts for body text; use them only for a logo or a short heading, if at all.

More text properties

HTML · runs live in the interactive lesson
<style>
  body { font-family: system-ui, sans-serif; margin: 16px; }
  .spaced { letter-spacing: .12em; text-transform: uppercase; font-size: .8rem; font-weight: 700; color: #6b7280; }
  .indent { text-indent: 2em; }
  .clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; max-width: 320px; }
  .balance { text-wrap: balance; max-width: 360px; font-size: 1.4rem; font-weight: 700; }
  .nums { font-variant-numeric: tabular-nums; }
  a { color: #1d4ed8; text-underline-offset: 3px; text-decoration-thickness: 2px; }
</style>
<p class="spaced">Our services</p>
<p class="balance">Website design, hosting and digital marketing for growing businesses</p>
<p class="clamp">This product description is long and will be cut after exactly two lines with an ellipsis, which keeps product cards in a grid the same height no matter how much text the seller typed.</p>
<p class="indent">Text indent pushes the first line in, like a printed book.</p>
<p class="nums">KSh 1,111.00<br>KSh 9,999.00</p>
<p>A <a href="#">well-styled link</a> with offset underline.</p>

tabular-nums makes every digit the same width so prices line up in tables.

Accessibility checklist for text

  • Never set body text below 16px, and let users zoom (don't block zoom in the viewport meta tag).
  • Use rem for font sizes so the user's browser setting is respected.
  • Don't use colour alone to show meaning (add underline to links in paragraphs).
  • Avoid long passages in all capitals or italics; they are harder to read.
  • Check contrast with DevTools or an online contrast checker.

Common mistakes

MistakeFix
Light grey text on white (#aaa on #fff)Use a darker grey like #374151
Full-width paragraphs on desktopmax-width: 65ch
Loading 6 font weightsLoad 2 or 3
font-size in px everywhererem for text so zoom settings work
Justified text on narrow screensLeft-align; justify causes big gaps

Practice

  1. Style an article page with a type scale of 5 steps in CSS variables.
  2. Make a hero heading fluid with clamp() from 1.8rem to 3.5rem.
  3. Create a pricing table where numbers line up using tabular-nums.
  4. Build product cards whose descriptions are clamped to 3 lines.
Think about it: Why is font-size: 1rem better than font-size: 16px for body text, even though they look the same by default?Show answer

Users with low vision often raise their browser's default font size. rem scales with that setting, so text grows as they expect; px ignores it in many browsers, keeping text small. Using rem respects the user's choice and improves accessibility.

Check yourself

  1. Which generic font family should end a font stack for normal text: serif, sans-serif or monospace?

    Show answer

    sans-serif

  2. Which property sets the space between lines of text?

    Show answer

    line-height

  3. What font-weight number is normal text?

    Show answer

    400

  4. Which property makes text uppercase without retyping it?

    Show answer

    text-transform

  5. Which CSS function sets a size with a minimum, a preferred value and a maximum?

    Show answer

    clamp

  6. Which max-width keeps paragraphs at a readable length using character units? (e.g. 65...)

    Show answer

    65ch

  7. Which @font-face setting shows fallback text immediately while the font loads?

    Show answer

    font-display: swap

  8. What minimum contrast ratio is recommended for body text (WCAG AA)?

    Show answer

    4.5:1

Exercise

Style the paragraph: give p a line-height of 1.6 and a font-family that ends with sans-serif.

Do this exercise in the live editor

Lesson 3 of 21 in CSS · Printable course notes