What CSS underline really is
When people say “CSS underline”, they usually mean “the underline drawn under text”.
In CSS, that underline is part of the text-decoration system.
Here’s the key idea:
-
The underline itself is controlled by
text-decoration-line(set it tounderline). -
The look of that underline is controlled by properties like
text-decoration-color,text-decoration-thickness,text-decoration-style, andtext-underline-offset. -
You can also use the shorthand
text-decorationto set multiple things at once.
Let’s start with the simplest underline possible, then we’ll level it up.
.demo {
text-decoration-line: underline;
}
.demo {
text-decoration-line: none;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 12px;
max-width: 720px;
}
.demo {
font-size: 28px;
font-weight: 700;
line-height: 1.2;
}
.note {
font-size: 14px;
opacity: 0.8;
}
Underlines are a text decoration.Click the CSS snippets to toggle underline on and off.
CSS underline property: the main players
You’ll often see “CSS underline property” in searches, but there isn’t a single property named underline.
Instead, you use one of these approaches:
-
Longhand (most explicit):
text-decoration-line: underline; -
Shorthand (most common):
text-decoration: underline;
The shorthand is convenient, but longhand is easier to read and tweak when you care about thickness, offset, style, and color.
.demo {
text-decoration: underline;
}
.demo {
text-decoration-line: underline;
}
.demo {
text-decoration: none;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 720px;
}
.demo {
font-size: 28px;
font-weight: 700;
line-height: 1.25;
}
.small {
font-size: 14px;
opacity: 0.85;
}
Shorthand vs longhand underline.Shorthand is quick. Longhand is great when you want fine control.
CSS underline text: the basic underline
The basic underline is just:
-
text-decoration-line: underline;
A very common real-world case is underlining links. You can underline any element containing text, not just <a>.
a {
text-decoration-line: underline;
}
a {
text-decoration-line: none;
}
.highlight {
text-decoration-line: underline;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
p {
font-size: 18px;
line-height: 1.55;
margin: 0;
}
a {
color: #1a56db;
font-weight: 650;
}
.highlight {
font-weight: 750;
}
This is a link inside a paragraph, and this is a non-link underline.
CSS underline color
Underlines don’t have to match the text color. Use text-decoration-color.
This is especially useful when you want a “highlight underline” style without changing the text itself.
-
text-decoration-color: hotpink; -
text-decoration-color: currentColor;(forces it to match text color)
.demo {
text-decoration-line: underline;
text-decoration-color: hotpink;
}
.demo {
text-decoration-line: underline;
text-decoration-color: #22c55e;
}
.demo {
color: #111;
text-decoration-line: underline;
text-decoration-color: currentColor;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 30px;
font-weight: 800;
line-height: 1.2;
}
.tip {
font-size: 14px;
opacity: 0.85;
}
Colorful underline, boring text.Underline color can be independent from the text color.
CSS underline width (thickness)
People often say “underline width”, but what they usually mean is underline thickness.
In CSS, that is text-decoration-thickness.
You can use keywords or a length:
-
Keywords:
auto,from-font -
Lengths:
2px,0.12em, etc.
Tip: em thickness scales with font size, which often looks more consistent across responsive text.
.demo {
text-decoration-line: underline;
text-decoration-thickness: 2px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 34px;
font-weight: 850;
line-height: 1.1;
}
.help {
font-size: 14px;
opacity: 0.85;
}
Thicker underline = louder underline.Use the slider to changetext-decoration-thickness.
CSS underline offset (spacing)
If your underline feels too close to the text (or crashes into descenders like g, y, p),
you want text-underline-offset.
- Small values: tight underline
- Larger values: more breathing room
.demo {
text-decoration-line: underline;
text-decoration-thickness: 3px;
text-underline-offset: 6px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 34px;
font-weight: 850;
line-height: 1.15;
}
.small {
font-size: 14px;
opacity: 0.85;
}
gyp jqy: watch the descenders.Adjusttext-underline-offsetto control spacing.
CSS underline style
Want dotted underlines? Dashed? Wavy? That’s text-decoration-style.
-
solid(default) -
dotted -
dashed -
wavy
.demo {
text-decoration-line: underline;
text-decoration-style: solid;
text-decoration-thickness: 3px;
}
.demo {
text-decoration-line: underline;
text-decoration-style: dotted;
text-decoration-thickness: 3px;
}
.demo {
text-decoration-line: underline;
text-decoration-style: dashed;
text-decoration-thickness: 3px;
}
.demo {
text-decoration-line: underline;
text-decoration-style: wavy;
text-decoration-color: #ef4444;
text-decoration-thickness: 2px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 34px;
font-weight: 850;
line-height: 1.1;
}
.note {
font-size: 14px;
opacity: 0.85;
}
Underline styles are a vibe.Try the different styles: solid, dotted, dashed, wavy.
Text-decoration shorthand: underline all-in-one
The text-decoration shorthand can set multiple parts in one line.
For example:
-
text-decoration: underline; -
text-decoration: underline wavy hotpink;
Shorthand is great for quick styling, but longhand is often easier to tweak later (especially when you start adding thickness and offset).
.demo {
text-decoration: underline;
}
.demo {
text-decoration: underline wavy #a855f7;
}
.demo {
text-decoration: underline dashed #22c55e;
text-decoration-thickness: 4px;
text-underline-offset: 7px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 34px;
font-weight: 850;
line-height: 1.1;
}
.note {
font-size: 14px;
opacity: 0.85;
}
Shorthand is quick, longhand is comfy.Notice how thickness and offset are still controlled with their own properties.
CSS underline on hover
Hover underlines are popular because they make text feel interactive (especially links). We’ll do two versions:
-
Animate underline thickness using
text-decoration-thickness. - Create a slick “draw-in” underline using a pseudo-element that animates left to right, and also animates out left to right.
Hover underline: animate text-decoration-thickness
This is the simplest “animated underline” trick:
- Start with a thin underline.
-
On hover, increase
text-decoration-thickness.
One small gotcha: not every browser animates every text-decoration detail perfectly. Still, this effect is often “good enough” and very easy to maintain.
a {
text-decoration-line: underline;
text-decoration-thickness: 1px;
text-underline-offset: 4px;
transition: text-decoration-thickness 200ms ease;
}
a:hover {
text-decoration-thickness: 5px;
}
a {
text-decoration-line: underline;
text-decoration-color: #22c55e;
text-decoration-thickness: 2px;
text-underline-offset: 5px;
transition: text-decoration-thickness 250ms ease, text-decoration-color 250ms ease;
}
a:hover {
text-decoration-thickness: 8px;
text-decoration-color: #ef4444;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 12px;
max-width: 760px;
}
p {
margin: 0;
font-size: 18px;
line-height: 1.55;
}
a {
color: #1a56db;
font-weight: 700;
}
.hint {
font-size: 14px;
opacity: 0.85;
}
Hover this link and watch the underline thicken.
Thickness + offset is a great combo for “premium” underlines.
Hover underline: pseudo-element draw-in (and draw-out) animation
If you want a super smooth underline animation (and consistent behavior), a pseudo-element is the classic move. The idea:
- Wrap the text in a link.
-
Use
::afteras the underline bar. -
Animate it with
transform: scaleX().
Let's go for an underline that:
- Animates in from left to right.
- Animates out from left to right.
.fancy-link {
position: relative;
text-decoration: none;
}
.fancy-link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 6px;
background: linear-gradient(90deg, #22c55e, #3b82f6);
border-radius: 999px;
transform: scaleX(0);
transform-origin: right;
transition: transform 260ms ease;
}
.fancy-link:hover::after {
transform: scaleX(1);
transform-origin: left;
}
.fancy-link {
position: relative;
text-decoration: none;
}
.fancy-link::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 4px;
background: currentColor;
transform: scaleX(0);
transform-origin: right;
transition: transform 240ms ease;
}
.fancy-link:hover::after {
transform: scaleX(1);
transform-origin: left;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 12px;
max-width: 760px;
}
p {
margin: 0;
font-size: 18px;
line-height: 1.6;
}
.fancy-link {
font-size: 28px;
font-weight: 850;
color: #111;
display: inline-block;
}
.sub {
font-size: 14px;
opacity: 0.85;
}
Hover: Underline that draws in
It animates in left → right and collapses toward the left when hover ends.
Learn more about pseudo-elements in the CSS ::before and ::after Pseudo-Elements Interactive Tutorial.
Extra polish and common gotchas
Gotcha: underline is not a border
Underlines are not borders. That’s why “underline width” isn’t really a thing.
You don’t set underline “width” like a line element. You style the decoration:
text-decoration-thickness, text-underline-offset, text-decoration-style, and text-decoration-color.
Gotcha: links need focus styles too
Hover is mouse-only. Keyboard users rely on focus.
If you remove default link underlines, add a clear :focus-visible style.
a {
text-decoration: none;
font-weight: 750;
}
a:focus-visible {
outline: 3px solid #111;
outline-offset: 4px;
text-decoration-line: underline;
text-decoration-thickness: 4px;
text-underline-offset: 6px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
p {
margin: 0;
font-size: 18px;
line-height: 1.6;
}
a {
color: #1a56db;
}
Use Tab to focus this link and see the focus-visible underline + outline.
Learn more about link styling in the CSS Link Interactive Tutorial.
Extra: skipping ink on descenders
Sometimes you want the underline to “skip” through descenders (like the tail of a g).
That behavior can be influenced by text-decoration-skip-ink.
-
autooften looks nicer for body text. -
noneforces the underline to draw straight through.
.demo {
text-decoration-line: underline;
text-decoration-thickness: 3px;
text-underline-offset: 3px;
text-decoration-skip-ink: auto;
}
.demo {
text-decoration-line: underline;
text-decoration-thickness: 3px;
text-underline-offset: 3px;
text-decoration-skip-ink: none;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrapper {
font-family: ui-sans-serif, system-ui, sans-serif;
padding: 18px;
display: grid;
gap: 10px;
max-width: 760px;
}
.demo {
font-size: 34px;
font-weight: 850;
line-height: 1.15;
}
.note {
font-size: 14px;
opacity: 0.85;
}
gyp jqy: skip ink or slice through?Comparetext-decoration-skip-ink: autovsnone.
Quick recap
-
Turn underline on with
text-decoration-line: underline(ortext-decoration: underline). -
Set underline color with
text-decoration-color. -
Set underline thickness (the “underline width” people mean) with
text-decoration-thickness. -
Control spacing with
text-underline-offset. -
Change the underline’s style with
text-decoration-style. -
For really smooth hover animations, use a pseudo-element underline with
transform: scaleX().
CSS underline conclusion
Underlines are a powerful text decoration that can be styled in many ways.
With properties like text-decoration-thickness, text-underline-offset, and text-decoration-style, you can create underlines that perfectly fit your design.
