Type something to search...
How to use text-decoration properties for better links?

How to use text-decoration properties for better links?

To make better links with text-decoration properties, keep the underline but refine it: set text-decoration-thickness to control how heavy the line is, text-underline-offset to move it away from the letters, text-decoration-color to give it a softer or brand colour, and leave text-decoration-skip-ink: auto on so the line breaks around descenders. Together these turn the browser's default underline, which can look heavy and crowded, into one that's clearly visible but easier to read. Add a hover state that changes the thickness or colour, and a strong :focus-visible outline for keyboard users. Keeping an underline on links in body text is also the simplest way to meet WCAG's requirement that links aren't identified by colour alone.

For years, designers removed link underlines because the default looked clumsy and there was no way to adjust it. Modern CSS fixes that, so you no longer have to choose between a visible link and an attractive one. In this article you'll learn each text-decoration property and what it does, how to build a refined underline, how to design hover, focus and visited states, the accessibility rules that apply, how to animate underlines, and how to handle links in navigation and buttons.

The Text Decoration Properties

text-decoration is a shorthand for several longhand properties, and there are related properties that control underline position. Here's the full set:

PropertyWhat it controlsExample
text-decoration-lineWhich line to drawunderline, overline, line-through, none
text-decoration-styleLine stylesolid, double, dotted, dashed, wavy
text-decoration-colorLine colourcurrentColor, #2563eb
text-decoration-thicknessLine weightauto, from-font, 0.08em, 2px
text-underline-offsetDistance from the textauto, 0.2em
text-underline-positionWhere the underline sitsauto, under, from-font
text-decoration-skip-inkWhether the line skips glyph descendersauto, none, all

All of these are supported in current versions of Chrome, Edge, Firefox and Safari. The shorthand accepts line, style, colour and, in most browsers, thickness. Because older Safari versions didn't accept thickness inside the shorthand, it's safest to write the thickness as a separate longhand.

text-decoration-thickness

The default thickness depends on the font and browser and is often too heavy for body text or too thin for bold headings. Using em keeps it proportional to the text size:

a {
  text-decoration-thickness: 0.08em;
}

from-font uses the thickness recommended by the font designer, if the font file includes one. Many well-made fonts do, so it's a reasonable choice if you trust the font.

text-underline-offset

The default underline sits close to the baseline and runs into descenders. Moving it down a little gives letters room to breathe:

a {
  text-underline-offset: 0.18em;
}

Again, em keeps the gap proportional at every size. Very large offsets can make the underline look disconnected from the text, especially with a tight line height, so values between about 0.12em and 0.25em work well.

text-decoration-skip-ink

With auto, the default in all current browsers, the underline breaks where it would cross descenders such as g, j, p, q and y. This is usually what you want, because it keeps letter shapes clear. Set none only if a design needs a continuous line, and test that descenders remain readable.

text-decoration-color

Separating the underline colour from the text colour lets you soften the line without making the text lighter:

a {
  color: #1d4ed8;
  text-decoration-color: rgb(29 78 216 / 0.4);
}

Using a semi-transparent version of the link colour keeps everything consistent if the colour changes in a dark theme.

Building a Refined Underline

Here's a complete, production-ready link style for article text:

:root {
  --link: #1d4ed8;
  --link-hover: #1e3a8a;
}

.prose a {
  color: var(--link);
  text-decoration-line: underline;
  text-decoration-thickness: 0.07em;
  text-decoration-color: color-mix(in srgb, var(--link) 45%, transparent);
  text-underline-offset: 0.18em;
  text-decoration-skip-ink: auto;
  transition:
    text-decoration-color 150ms ease,
    text-decoration-thickness 150ms ease;
}

.prose a:hover {
  color: var(--link-hover);
  text-decoration-color: currentColor;
  text-decoration-thickness: 0.12em;
}
<p class="prose">
  Read our <a href="/guides/getting-started">getting started guide</a> before
  you configure your first project.
</p>

At rest, the link is blue with a lighter, thin underline. On hover, the underline becomes solid and thicker, giving clear feedback without any layout shift. The color-mix() function is supported in all current major browsers; if you need older browser support, use a fixed rgb() value with alpha instead.

Using the Shorthand

If you prefer fewer lines, the shorthand works for line, style and colour:

.prose a {
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

A dotted underline is a common convention for abbreviations with a tooltip, so be careful about using it for ordinary links, where it can be confused with an abbr element.

Hover, Focus, Active and Visited States

Links need distinct states so users know where they are and what they've done.

Focus

Keyboard users navigate links with the Tab key, and they need to see which one is focused. WCAG 2.2 Success Criterion 2.4.7 (Focus Visible) requires a visible focus indicator. :focus-visible shows it for keyboard navigation without showing it on every mouse click:

.prose a:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
  border-radius: 2px;
  text-decoration-color: currentColor;
}

Never remove focus styles with outline: none unless you replace them with something equally visible.

Active

The active state appears while the link is being clicked or tapped. A small change is enough:

.prose a:active {
  text-decoration-thickness: 0.16em;
}

Visited

Visited styles help users track which pages they've already read, which is especially useful in long lists of links such as search results or documentation indexes. For privacy reasons, browsers restrict :visited to colour-related properties, including color and text-decoration-color:

.prose a:visited {
  color: #6d28d9;
  text-decoration-color: rgb(109 40 217 / 0.45);
}

Thickness and offset changes won't apply to visited links, because browsers deliberately ignore them.

Accessibility Requirements for Links

WCAG 2.2 Success Criterion 1.4.1 (Use of Color) says colour must not be the only visual means of conveying information. For links in a block of text, that means a link that differs from surrounding text only by colour is a problem for people who can't distinguish the colours.

There are two ways to meet the requirement:

  • Keep an underline, or another non-colour cue: an underline, bold weight or icon on links in body text satisfies it directly. This is the simplest and most robust approach.
  • Use colour with sufficient contrast plus a cue on interaction: W3C's technique G183 describes links whose colour has at least a 3:1 contrast ratio with the surrounding text, and which gain an extra visual cue, such as an underline, on hover and focus.

The second approach is harder than it sounds. Finding a link colour that has 4.5:1 contrast with the background (for SC 1.4.3) and 3:1 contrast with black or dark grey body text is often impossible. An underline avoids the problem.

The underline itself doesn't have a strict contrast requirement under WCAG when the link text already has good contrast, but a very faint underline does little for users who rely on it. Keep its colour clearly visible against the background.

Links in Navigation and Buttons

The underline rule mainly applies to links within text. In places where it's obvious that items are links, such as a site navigation bar, a card that's entirely clickable or a button-styled link, removing the underline is common and usually fine:

.site-nav a {
  color: inherit;
  text-decoration-line: none;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  text-decoration-line: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
}

The current page link keeps an underline, which gives a non-colour cue for location, and the large offset turns it into a neat indicator bar.

Animating Underlines

Several text-decoration properties are animatable: text-decoration-color, text-decoration-thickness and text-underline-offset can all be transitioned in current browsers. A subtle offset change makes a pleasant hover:

.prose a {
  text-underline-offset: 0.15em;
  transition: text-underline-offset 150ms ease;
}

.prose a:hover {
  text-underline-offset: 0.28em;
}

The Background Gradient Technique

For effects that text-decoration can't produce, such as an underline that grows from left to right, use a background gradient instead:

.fancy-link {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 0.08em;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size 250ms ease;
  padding-bottom: 0.05em;
}

.fancy-link:hover,
.fancy-link:focus-visible {
  background-size: 100% 0.08em;
}

@media (prefers-reduced-motion: reduce) {
  .fancy-link {
    transition: none;
  }
}

This works across multiple lines, because backgrounds on inline elements follow the line boxes. Note the trade-off: it doesn't skip descenders, and at rest there's no underline, so use it for navigation or headings rather than links in body text. The prefers-reduced-motion query respects users who have asked their system to minimise animation.

Other Uses for Text Decoration

The same properties are useful beyond links:

  • Spelling and grammar hints: a wavy red underline, text-decoration: underline wavy #dc2626, imitates the familiar editor convention for marking errors in an interface.
  • Deleted text: del elements use line-through. You can soften it with text-decoration-color and keep the text readable.
  • Abbreviations: abbr[title] elements get a dotted underline in most browsers. Adjust it with text-underline-offset to match your link style.
  • Inserted text: ins elements are underlined by default; you might give them a coloured background instead so they don't look like links.
del {
  text-decoration-color: rgb(220 38 38 / 0.7);
  text-decoration-thickness: 0.1em;
}

ins {
  text-decoration-line: none;
  background: #dcfce7;
}

abbr[title] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
}

A Quick Audit Script

To find links in your content that have lost their underline, run this in the console on a content-heavy page:

const bare = [...document.querySelectorAll("main p a, main li a")].filter((a) => {
  const style = getComputedStyle(a);
  return !style.textDecorationLine.includes("underline");
});

console.log(`${bare.length} in-text links without an underline`);
bare.forEach((a) => console.log(a.textContent.trim(), a.href));
2 in-text links without an underline
pricing page https://example.com/pricing
contact us https://example.com/contact

Any link listed is relying on colour alone, so check it against the use of colour criterion.


FAQ: Text Decoration for Links

Links within paragraphs and lists should generally be underlined, because it's the clearest non-colour cue. Links in navigation menus, buttons and clearly clickable cards can go without an underline when their role is obvious from the design.

Use text-decoration-thickness with a small value such as 0.06em or 1px. Using em keeps the thickness proportional to the font size, so it looks right in both body text and headings.

Use text-underline-offset, for example 0.18em. It moves the underline further from the baseline so it no longer crowds descenders.

Yes. Text-decoration-color sets the underline colour independently. A semi-transparent version of the link colour is a common choice.

Browsers restrict the visited pseudo-class to colour properties to protect users' browsing history. You can change color and text-decoration-color on visited links, but not thickness or offset.

It can be. If links in a block of text are distinguished by colour alone, they may fail success criterion 1.4.1. You need either a non-colour cue such as an underline, or a link colour with at least 3:1 contrast against the surrounding text plus an extra cue on hover and focus.


Conclusion

Modern text-decoration properties make it easy to keep link underlines and still have them look good. A slightly thinner line set with text-decoration-thickness, a little more space from text-underline-offset, a softer text-decoration-color and the default skip-ink behaviour give you underlines that are clearly visible and comfortable to read. Hover, focus and visited states then build on that foundation with small, purposeful changes.

Keep underlines on links within text so you never rely on colour alone, give keyboard users a strong :focus-visible style, and save underline-free designs for navigation and buttons where the role is obvious. Use transitions sparingly and respect reduced motion preferences. The result is links that look considered, work for everyone and need very little CSS.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper