CSSBeginner

CSS Text and Fonts: font-family, Size, Weight, Line Height

Style text with font-family, font-size, font-weight, line-height and web fonts, and see exactly which class or id styles which HTML element.

All CSS lessons

What you will learn

Most of the web is text, so text styling is where CSS pays off first. In this lesson you will learn the properties that control the font (font-family, font-size, font-weight, font-style), the spacing between lines (line-height), a few handy text properties, and how to use web fonts such as Google Fonts. Just as important, you will see exactly which class or id is attached to which HTML element, so you always know what a selector is pointing at.

The HTML we will style

Every example in this lesson runs against one small blog post. Read the HTML first, and notice the class and id attributes. Those are the “handles” that our CSS will grab.

<article class="post">
  <p class="category">CSS Basics</p>
  <h1 id="post-title">Why Typography Matters</h1>
  <p class="byline">By Aisha Khan · 5 min read</p>

  <p class="lead">Good text styling makes a page easier to read before anyone reads a single word.</p>

  <h2 class="section-title">Pick readable fonts</h2>
  <p>Body text should feel calm. Choose a clean font, a comfortable size and enough space between the lines.</p>
  <p>Use <span class="highlight">one or two fonts</span> at most. Too many fonts make a page look messy.</p>

  <blockquote class="quote">Readable text is the kindest thing you can give a visitor.</blockquote>

  <p class="note">Tip: style the body text first, then the headings.</p>
</article>

Here is the map from selector to element:

Selector Matches this element Its job
.post the <article> wrapper around everything
.category the first <p> small label above the title
#post-title the <h1> the main title
.byline the <p> with the author name small grey line
.lead the first big <p> introduction paragraph
.section-title the <h2> section heading
.highlight the <span> inside a paragraph important words
.quote the <blockquote> a pull quote
.note the last <p> small tip at the end

Two plain <p> elements have no class at all. You can still style them with the type selector p, or by targeting .post p.

font-family: choosing the typeface

font-family sets the typeface of the text.

/* Styles the <article class="post"> and, through it, everything inside */
.post {
  font-family: Arial, Helvetica, sans-serif;
}

Notice that there is a list of fonts. The browser tries them left to right and uses the first one that is installed on the visitor’s device. This list is called a font stack. The last entry should always be a generic family, a safety net that every device understands:

Generic family Look Typical use
serif letters with small strokes at the ends (Times, Georgia) books, articles, elegant headings
sans-serif clean, no strokes (Arial, Helvetica) websites, apps, body text
monospace every letter the same width (Courier, Consolas) code
system-ui the visitor’s own operating system font fast, native-looking interfaces
cursive and fantasy decorative rarely a good idea

A few more rules:

  • Font names with spaces should be in quotes: "Times New Roman", "Segoe UI".
  • Generic families are never quoted: serif, not "serif".
  • Separate names with commas.

Inheritance: why we style .post, not every element

Here is a very useful idea. Text properties such as font-family, font-size, color and line-height are inherited. That means when you set them on a parent, all its children (the paragraphs, headings and spans inside) automatically use the same value, unless they have their own rule.

That is why setting font-family on the .post wrapper is enough to change the font of the whole article. You can then override it for one element:

.post {
  font-family: Arial, Helvetica, sans-serif;
}

/* Only the <h1 id="post-title"> gets a different font */
#post-title {
  font-family: Georgia, "Times New Roman", serif;
}

In real projects you usually set the base font once on body, and every element inherits it.

font-size: how big is the text?

/* the <p class="category"> */
.category {
  font-size: 14px;
}

/* the <h1 id="post-title"> */
#post-title {
  font-size: 40px;
}

/* the <p class="lead"> */
.lead {
  font-size: 20px;
}

/* the <h2 class="section-title"> */
.section-title {
  font-size: 28px;
}

For now we use px (pixels), which is easy to picture. The CSS Units lesson explains rem and em, which are usually a better choice. Some useful facts:

  • Browsers make ordinary text 16px by default.
  • Body text between 16px and 20px is comfortable to read. Avoid going below 14px for anything important.
  • Headings are bigger because the browser gives them a larger default size, not because of their level number. You can change them at will.

font-weight: thin or bold?

/* the <span class="highlight"> inside the paragraph */
.highlight {
  font-weight: bold;
}

/* the <p class="category"> */
.category {
  font-weight: 700;
}

You can use the keywords normal and bold, or numbers from 100 to 900 in steps of 100:

  • 400 is the same as normal.
  • 700 is the same as bold.
  • Other numbers (300 light, 600 semi-bold, 800 extra-bold) only look different if the font actually includes that weight. Many fonts have only 400 and 700, so 600 may look exactly like 700.

Headings are already bold by default. Write font-weight: normal if you want a lighter heading.

font-style: italic text

/* the <blockquote class="quote"> */
.quote {
  font-style: italic;
}

The values are normal and italic. Use font-style: normal to remove italics from something the browser italicises by default.

line-height: the space between lines

line-height sets the height of each line of text. It is the single easiest way to make paragraphs look more professional.

.post {
  line-height: 1.6;
}

Write it as a plain number with no unit. 1.6 means “1.6 times the font size” for every element, so a 40px heading gets a 64px line and a 14px note gets a 22px line. Guidelines:

  • Body text: between 1.5 and 1.7.
  • Big headings: tighter, around 1.1 to 1.3, because large text with loose lines looks disconnected.
  • Below 1.2 text becomes cramped and hard to read.
#post-title {
  font-size: 40px;
  line-height: 1.2;
}

Why no unit? With line-height: 1.6em or 24px, the value is calculated once on the parent and then handed down to children as a fixed length. A child with bigger text then gets lines that are too small and overlap. The unitless number is recalculated for every element, so it always fits.

Other useful text properties

A few properties you will use almost as often:

/* the <p class="category"> */
.category {
  text-transform: uppercase;
  letter-spacing: 2px;
}

/* the <blockquote class="quote"> */
.quote {
  text-align: center;
}

/* the <span class="highlight"> */
.highlight {
  text-decoration: underline;
}

/* the <p class="byline"> */
.byline {
  color: gray;
}
  • text-align aligns text inside its box: left, right, center or justify.
  • text-transform changes capital letters without touching the HTML: uppercase, lowercase or capitalize.
  • letter-spacing adds space between letters. A little on small uppercase text looks polished.
  • text-decoration adds underline, line-through or overline, or removes a line with none (browsers underline links by default).

Web fonts: fonts that are not on the visitor’s device

Fonts like Arial only work because they are already installed. A web font is downloaded together with your page, so you can use any typeface and it looks the same everywhere. There are two ways to add one.

Option 1: Google Fonts (easiest)

  1. Go to Google Fonts, pick a font (for example Poppins) and choose the weights you need, such as 400 and 700.
  2. Copy the <link> tags it gives you into the <head> of your HTML, before your own stylesheet:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
  1. Use the font name in your CSS, with a fallback in case the font fails to load:
.post {
  font-family: "Poppins", Arial, sans-serif;
}

In the MyCodeNest editor: the preview may block requests to outside websites, so a Google Font might not appear there. Test web fonts in your own project on your computer.

Option 2: your own font files

If you have a font file (.woff2 is the best format), declare it with @font-face and then use it like any other font:

@font-face {
  font-family: "MyFont";
  src: url("fonts/myfont.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

.post {
  font-family: "MyFont", Arial, sans-serif;
}

font-display: swap tells the browser to show the fallback font immediately and switch when the web font arrives, so text is never invisible while loading.

Web font good habits

  • Use at most two font families on a site, and only the weights you really use. Each extra file makes the page slower.
  • Always list a fallback font stack ending with a generic family.
  • Make sure the font is readable at small sizes. Fancy fonts belong in headings, not body text.

Putting it together

Here is the complete stylesheet for the blog post. Compare each rule with the map table above:

/* <article class="post">: base text style, inherited by all children */
.post {
  font-family: Arial, Helvetica, sans-serif;
  line-height: 1.6;
  color: #222;
}

/* <p class="category"> */
.category {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: royalblue;
}

/* <h1 id="post-title"> */
#post-title {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 40px;
  line-height: 1.2;
}

/* <p class="byline"> */
.byline {
  font-size: 15px;
  color: gray;
}

/* <p class="lead"> */
.lead {
  font-size: 20px;
}

/* <h2 class="section-title"> */
.section-title {
  font-size: 28px;
}

/* <span class="highlight"> */
.highlight {
  font-weight: 700;
  text-decoration: underline;
}

/* <blockquote class="quote"> */
.quote {
  font-size: 22px;
  font-style: italic;
  text-align: center;
}

/* <p class="note"> */
.note {
  font-size: 14px;
  color: dimgray;
}

Common mistakes

  • Forgetting the fallback fonts. If the first font is missing, the browser falls back to its default, which is usually a serif font. End every stack with serif, sans-serif or monospace.
  • Quoting generic families ("sans-serif") or forgetting the quotes around names with spaces.
  • Using line-height with a unit such as 24px on a parent, which gives the wrong spacing to bigger children.
  • Writing font-size: 20 with no unit, or text-color/font-color instead of color.
  • Expecting font-weight: 600 to look different when the font has only 400 and 700.
  • Loading too many fonts and weights, which slows the page down.
  • Setting the font on every element instead of once on a parent and letting it inherit.
  • Low contrast, for example light gray text on white.

Practice

  1. Click Practice in Editor. Change the article font to Verdana, Geneva, sans-serif, then change the heading font to a monospace stack such as "Courier New", Courier, monospace.
  2. Add rules for .category, .byline and .lead so that the label is small, bold, uppercase and blue, the byline is small and gray, and the lead paragraph is 20px.
  3. Change line-height on .post to 1, then 2, then 1.6. Which is the most comfortable to read?
  4. Make the .quote italic and centred, and give the .highlight span a bold weight.
  5. Style the two plain paragraphs without adding any class, using the selector .post p. Which other paragraphs does this selector change? (Hint: it matches every <p> inside .post, including the ones that also have a class.)
  6. Add a Google Font of your choice to a page on your computer, and use it for the heading only, with a fallback.

Recap

  • font-family takes a font stack: your first choice, backups, then a generic family (serif, sans-serif, monospace).
  • Text properties like font-family, color and line-height are inherited, so set them once on a parent.
  • font-size, font-weight (400 normal, 700 bold) and font-style change the look of the letters.
  • Use a unitless line-height of about 1.5 to 1.7 for body text.
  • text-align, text-transform, letter-spacing and text-decoration handle the rest of everyday text styling.
  • Web fonts come from Google Fonts or @font-face. Use few families and weights, and always add a fallback.
  • Next you will learn the different units that CSS uses for sizes.