Improved CSS Text-Stroke
Historically, applying an outer stroke to text via CSS has been tricky.
All major browsers have long supported these (stubbornly vendor-prefixed) properties:
-webkit-text-stroke-webkit-text-stroke-color-webkit-text-stroke-width
But these always center-align the outline, intruding on text therein. For anything more than a hairline stroke on some decently heavy type, things get real ugly real fast:
.example {
-webkit-text-stroke: 0.125em white;
}
(It’s even worse with variable fonts, as documented in this Mona Sans issue and on Stack Overflow.)
Web designers are tenacious, so of course they found workarounds:
- Set text shadows in every cardinal direction (Chris Coyier, 2010)
- Duplicate text, apply stroke to the bottom “layer” (James Nowland, 2015)
- Use an SVG filter (Dudley Storey, 2016)
Most of the time, though, I just avoided the effect in my work unless it was a key design detail.
But while I wasn’t looking, things improved!
Just the other day, my TTF collaborator Scott Kellum pointed out to me that the paint-order property, available for quite a while in WebKit (Safari) and Gecko (Firefox), gained Chromium support in 2024!
Which means we can now explicitly position the text stroke beneath the text fill, preventing it from crowding out the letterforms:
paint-order applied, the text remains legible atop the stroke..example {
paint-order: stroke fill;
-webkit-text-stroke: 0.125em white;
}
As of this writing, there’s still room for improvement:
- Strokes can get pretty pointy! It’d be great if properties like
stroke-linejoinandstroke-miterlimitworked here. - The shape of the stroke seems rounder in Firefox than in other browsers.
- Any
text-shadowpaints above the stroke. (My demos in this post use adrop-shadowfilter instead.) - Typing that vendor prefix feels pretty silly nearly twenty years later.
But I thought I’d share in case this flew under anyone else’s radar.