March 9, 2021

Better CSS strikethroughs

A quick tip to control the seemingly uncontrollable text-decoration: line-through.

Too long, didn’t read: Use text-underline-offset and @supports to progressively enhance finer control over your strikethroughs – see the code.


Text decoration has been around since CSS Level 1, and it works.

More recently the introduction of text-decoration- modifying properties have allowed a greater control over the line, but there are still limitations…

The problem

I ran into this while trying to get a more aesthetic position for the strikethrough on my journal post about redesigning this site:

The default position was too high.

A screenshot showing the unbalanced strikethrough with the default text-decoration value
This doesn’t actually cross the text out because it sits at 50% of the cap-height, not 50% of the x-height.

You might ask why this matters, but these fine details are what stand in the way of something looking truly polished (not perfect mind you), so I set about fixing it!

I knew that there was an offset property for text decoration, so I tried text-decoration-offset only to find out that only underlines could have an offset… go figure.

Frustrated – but not beaten – I considered that text-decoration: line-through is basically an underline, but positioned in the middle. Could I fake a strikethrough using an offset underline?

del {
  text-decoration: underline;
  /* -0.33em was the value (notice relative units to ensure that it scales as the
     parent `font-size` scales) needed for Clone Rounded, but for other webfonts this
     will need to be tinkered with slightly to get the right positioning. */
  text-underline-offset: -0.33em;
}
A screenshot showing the obscured line-through
The line is now correctly positioned, but the ink-skip means that it isn’t behaving as we would want it to.

The complete solution

The ink-skip issue is fixed by adding text-decoration-skip-ink: none;.

While text-underline-offset is reasonably well supported, it is still new and can be wrapped in a @supports condition to be sure that any browsers that don’t support it fall back to text-decoration: line-through.

del {
  text-decoration: line-through;
}

@supports(text-underline-offset: 1em) {
  del
    text-decoration: underline;
    text-underline-offset: -0.33em;
    text-decoration-skip-ink: none;
  }
}
A screenshot showing the unbalanced strikethrough with the default text-decoration valueA screenshot showing the properly aligned strikethrough
Before and after… Great success!

Caveats

Sadly this comes at a compromise. As the underline is rendered behind the text, using text-decoration-color no longer has the desired effect. Until we get something like text-decoration-offset we have to choose one or the other.


Thanks for taking the time to read this!

If you enjoyed it, and think others would benefit from the read then feel free to share it on Twitter (or elsewhere). I’m always up for a discussion about anything I’ve written too, so get in touch if you want to chat!

If you’ve spotted something out of place or something needs correcting, feel free to open a PR for this entry, raise an issue, or let me know.

A newer entry The last pizza recipe you’ll ever need

March 29, 2021 A short journal entry to immortalise the rebuild of our dad’s pizza recipe that turned into a Twitter embed adventure!

An older entry The right tool for the wrong person

December 20, 2020 Revisiting some old projects has left me wondering whether we choose the right tools for the wrong people, and how to avoid overcomplicating the beautiful simplicity of HTML and CSS.