
text-decoration-inset is Like Padding for Text Decorations
text-decoration-inset is Like Padding for Text Decorations êŽë š
The text-decoration-inset CSS property solves a problem that weâve had since the beginning of the web, which is that text decorations such as underlines extend beyond the first and last characters (to the edges of the content box, to be specific), resulting in vertical misalignment.

I say itâs a problem âweâveâ had rather sheepishly because maybe you, like some users, donât actually care. But if youâre a funny bunny like me (I think âdesignerâ is the technical term) then it most likely drives you crazy.
That being said, itâs not a problem that Iâve tried to fix because the juice just isnât worth the squeeze. The best fix is probably text-decoration: none and ::after with a custom background, but this can be a bit finicky and Iâd rather use all of the features that come with native text decorations, such as text-decoration-thickness, text-underline-position (which enables us to change the position of the underline relative to the fontâs internal metrics; the baseline, for example), and text-underline-offset (which determines the offset from that position).
So, how does text-decoration-inset work? Well, if I trim an underline just enough for it to vertically align with the text, I wind up with this instead (this only works in Firefox 146, by the way):

However, you can actually trim the decorations as much as you want, which enables us to create some really cool ones and even transition or animate them. Letâs take a quick look, shall we?
text-decoration-inset basic usage
text-decoration-inset, formerly text-decoration-trim (w3c/csswg-drafts), enables us to clip from the ends of the underline or whatever text-decoration-line is computed. This is the syntax:
text-decoration-inset: <left-inset> <right-inset>;
Yes, this means that we can set different inset values for the left and right sides.
These values must be <length>s, but we can use relative lengths such as em units, which are relative to the computed font-size. So, if the font-size changes, the insets scale with it. For example, in the demo above, 0.076em (which is what Iâve set as the left inset) means 7.6% of the computed font-size, and thatâs the value that makes the left inset align with the left stem of the letter âNâ and other left stems. This value was determined by trial and error, but it only needs to be determined once for each font.
If that first letter was, say, W? Yeah, then the inset wouldnât align, so itâs not a perfect solution. Iâd say that itâs suitable for when you know what the content will be.
Maybe the W3C will come up with a solution for vertically aligning text decorations as well as multiple lines of text both accurately and automatically. Until then, this is still a cool solution that enables us to create perfectly aligned effects like this (this demo uses an overline and an underline, and a whole âlotta text-decoration-thickness of course):
Animating text-decoration-inset
text-decoration-inset is more interesting when we start to think about transitions/animations. We often animate underlines, or should I say faux ::after underlines, but with text-decoration-inset we can do it natively. In the example below I multiply the insets by ten on :hover. Nothing too crazy, but remember that we can only use <length> values, so try to use em units, or at least test the text with different font sizes.
Again, Firefox 146+ required at the moment:
a {
transition: 300ms;
text-decoration-inset: 0.046em 0.009em;
&:hover {
text-decoration-inset: calc(0.046em * 10);
}
}
Getting a bit more ambitious now, this next demo leverages a CSS @keyframes animation to create that shooting star underline effect. How it works is that we push the left inset all the way to the other side â but <length>s only, remember? We canât use 100% here, so instead Iâve determined that the width of the element is 4.5em and used that as the value instead (the more precise we are, the better the animation or transition). Check the code comments for a full explanation:
a {
/*
The value at the start and end of the
animation, as well as the default value
*/
text-decoration-inset: 0.046em 0.009em;
&:hover {
animation: 1s next-level;
}
}
@keyframes next-level {
/* By half-way through the animation... */
50% {
/*
...the left inset has shifted 4.5em,
which is the full width of the element
*/
text-decoration-inset: 4.5em 0.009em;
/* Itâs faded out as well */
text-decoration-color: transparent;
}
/* Immediately after that... */
50.999% {
/* ...both insets are set to the left */
text-decoration-inset: 0.046em 4.5em;
}
/* Then it animates back to the default value */
}
Overall, text-decoration-inset is a nice feature. It isnât without its flaws, but no feature ever is. Personally, anything that helps me to refine a detail natively is very much welcome, and with text-decoration-inset weâre able to refine two â the text decoration alignment (relative to the text) and the text decoration transition or animation.