Styling Text

CSS · Lesson 13 of 55 7 min read Updated

Most of the web is text: articles, notices, product descriptions, error messages. A page with good colours but cramped, wide or badly wrapped text is still tiring to read. A few well-chosen text properties make a big difference.

In this lesson you will control alignment, line spacing and line length, style underlines, change letter case and spacing, cut long text with an ellipsis, and balance the lines of headings. Choosing and loading fonts is covered next in Fonts & Web Fonts.

Readable paragraphs

Three properties decide how comfortable a paragraph is to read:

  • line-height sets the height of each line. For body text, 1.5 to 1.7 works well. Write it without a unit: a unitless value is multiplied by each element's own font size, so it stays right when a child has bigger text.
  • Line length: lines that are too long make the eye lose its place. Around 60 to 75 characters per line is comfortable, and max-width: 65ch gives you that.
  • text-align: use start (the default for left-to-right languages) for body text. center suits short headings and buttons, not paragraphs.
HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Readable text</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; color: #22272e; }
    article { max-width: 65ch; margin-inline: auto; }
    p { line-height: 1.65; font-size: 1.0625rem; }
    .label {
      text-transform: uppercase;
      letter-spacing: 0.08em;
      font-size: 0.8rem;
      font-weight: 600;
      color: oklch(50% 0.13 250);
    }
    h1 { line-height: 1.15; text-align: center; }
    a {
      color: oklch(48% 0.16 250);
      text-decoration-thickness: 2px;
      text-underline-offset: 0.2em;
    }
  </style>
</head>
<body>
  <article>
    <p class="label">Travel diary</p>
    <h1>Two days in Kochi</h1>
    <p>Rohan started his first morning at Fort Kochi beach, watching the fishermen lift the huge Chinese fishing nets out of the water. By noon he had walked through Jew Town, tried banana chips straight from the fryer and found a quiet cafe with filter coffee.</p>
    <p>On the second day he took the ferry to Vypin Island. The ticket cost only a few rupees, and the view of the harbour was the best part of the trip. <a href="#">Read his full itinerary</a>.</p>
  </article>
</body>
</html>

The article never grows wider than about 65 characters, even on a big screen. The small "Travel diary" label is written in normal case in the HTML and turned into capitals with text-transform, with a little extra letter-spacing because capitals look cramped otherwise. The link has a thicker underline that sits slightly below the letters.

Underlines and decoration

text-decoration adds lines to text. It is a shorthand for the line type, style, colour and thickness:

CSS
a {
  text-decoration: underline dotted oklch(55% 0.15 30);
  text-underline-offset: 3px;
}
a:hover {
  text-decoration-style: solid;
}
.old-price {
  text-decoration: line-through;
  color: #6b7280;
}

Links in running text should stay underlined, so people can spot them without relying on colour. Use text-underline-offset and text-decoration-thickness to make the underline neater rather than removing it. The line-through value is handy for an old price next to a sale price.

Spacing and case

  • letter-spacing adds or removes space between letters. Use small em values like 0.05em, mostly for capitals and small labels.
  • word-spacing changes the space between words; you will rarely need it.
  • text-indent indents the first line of a block.
  • text-transform changes case: uppercase, lowercase or capitalize (first letter of each word).

Long words and long lines

Long words and URLs can overflow narrow boxes on phones. Two properties help:

CSS
.comment {
  overflow-wrap: anywhere;   /* break long URLs or words if they do not fit */
}
.article {
  hyphens: auto;             /* add hyphens where the language allows */
}

hyphens: auto needs the correct lang attribute on the page, such as <html lang="en">, because hyphenation rules differ by language.

Truncating text with an ellipsis

To keep a product name on one line and show "..." when it is too long, you need three properties together:

CSS
.product-name {
  white-space: nowrap;      /* keep it on one line */
  overflow: hidden;         /* hide what does not fit */
  text-overflow: ellipsis;  /* show ... at the cut */
}

For several lines, for example a three-line summary on a card, use the line-clamp pattern. Despite the -webkit- prefixes it works in all major browsers:

CSS
.summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

Remember that truncated text is hidden from sighted users. Make sure the full text is available somewhere, such as on the product page.

Better line breaks with text-wrap

Headings often wrap badly: a long first line and a single lonely word on the second. text-wrap: balance asks the browser to make the lines roughly equal in length. It is meant for short text such as headings and captions, and it is supported in current versions of all major browsers.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>text-wrap</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; }
    h2 { width: 18rem; font-size: 1.6rem; line-height: 1.2; border: 1px dashed #b8c2cf; padding: 0.5rem; }
    .balanced { text-wrap: balance; }
    .name {
      width: 12rem;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      border: 1px dashed #b8c2cf;
      padding: 0.5rem;
    }
  </style>
</head>
<body>
  <h2>Admissions open for the new academic year in Jaipur</h2>
  <h2 class="balanced">Admissions open for the new academic year in Jaipur</h2>
  <p class="name">Stainless steel pressure cooker, 5 litre, induction base</p>
</body>
</html>

The first heading has uneven lines. The second, with text-wrap: balance, spreads the words evenly across its lines. The product name is cut with an ellipsis.

Common mistakes

  • Line-height with units. line-height: 24px stays 24px even for a 40px heading inside, so lines overlap. Use a number such as 1.5.
  • Very wide paragraphs. Full-width text on a desktop is hard to read. Limit it with max-width: 65ch.
  • Justified text on narrow screens. text-align: justify creates big gaps between words on phones. Prefer start.
  • Removing link underlines. Users then have to guess what is clickable from colour alone.
  • Ellipsis without nowrap and overflow. text-overflow does nothing on its own.

Key points

  • Use a unitless line-height of about 1.5 to 1.7 and limit paragraphs to about 65ch wide.
  • Keep body text aligned to start; centre only short text.
  • Keep link underlines and refine them with text-underline-offset and text-decoration-thickness.
  • Use text-transform for capitals rather than typing capitals in HTML.
  • text-overflow: ellipsis needs white-space: nowrap and overflow: hidden.
  • text-wrap: balance evens out heading lines; text-wrap: pretty improves paragraph endings where supported.

Exercise

Style a short news article about a school sports day in Lucknow. Limit the article to 60ch, give paragraphs a comfortable line height, balance the heading, add an uppercase category label with letter spacing, and show the old entry fee of ₹200 crossed out next to the new fee of ₹150.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Sports day</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; }
    article { max-width: 60ch; margin-inline: auto; }
    .category { text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.8rem; color: #8a3324; }
    h1 { text-wrap: balance; line-height: 1.2; }
    p { line-height: 1.6; }
    .old { text-decoration: line-through; color: #6b7280; }
  </style>
</head>
<body>
  <article>
    <p class="category">School news</p>
    <h1>Annual sports day returns to the city stadium this December</h1>
    <p>Students from classes 6 to 12 will compete in athletics, kabaddi and relay races.</p>
    <p>Entry fee for parents: <span class="old">₹200</span> ₹150</p>
  </article>
</body>
</html>

The category text is typed in normal case and shown in capitals by CSS, and the old fee keeps its meaning while looking crossed out.

Quick Quiz

1. Which line-height is the best choice for body text?

2. Which properties are needed together for a single-line ellipsis?

3. What does text-wrap: balance do?

4. Why use text-transform: uppercase instead of typing capitals in HTML?

Learn CSS with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call