I read a Medium post by Marcin Wichary some time ago about crafting underlines on links. As he puts it in that 2014 article…

How hard could it be to draw a horizontal line on the screen? But simple things are rarely simple under the surface… at least if they are worth anything. Typography, likewise, is a game of nuance. This is a story on how a quick evening project to fix the appearance of underlined Medium links turned into a month-long endeavor.

They tried all sorts of things, like applying a CSS text shadow or text stroke to paint over the underline and simulate a gap between the underline and the text. Things got unbelievably tricky when it came to positioning without making the whole darn thing too expensive to make it worthwhile.

The goal seems simple, doesn’t it?  The way browsers style text underlines looks as terrible as it is hard to read.  If we could just, somehow, have those underlines skip the descenders, my typography heart would sing.

Perhaps giving up too quickly, I came to the conclusion this just wasn’t going to be possible until there was a CSS property that included something like text-underline-skip: true; or whatever. C’est la vie.

That is, until about 8 months ago, I updated my iOS devices and started noticing the links in emails and text messages were skipping the descenders.  How can this be?!

I must have you!

I Googled until my fingers bled, desperate to discover how they pulled it off and how I could use the same or similar technique in our web design projects.

Like Medium years before me, I ran into all sorts of issues trying to do it with pure CSS. I was defeated again.

Two Javascript Libraries Emerge

Out of this frustration, shared by many typography nerds like me, emerged two javascript libraries that make something this complex an absolute breeze: UnderlineJS and SmartUnderline.

Both libraries search your document looking for things with an underline text-decoration and apply some tricks to achieve this effect.  Both are highly experimental and their differences subtle.


SmartUnderline searches your document looking for things with an underline text-decoration (even in external CSS) and applies a text-shadow that’s the same color as the background along with a horizontal line. It layers these together and the result appears to clear the descenders.  It’s also very good at handling positioning which is where I got stuck.

It’s a lot more light-weight and has fewer performance penalties on mobile than UnderlineJS.

However, SmartUnderline was built for one thing and one thing only–skipping descenders.

Clear Decenders

It does require the text sit on top of a solid background color.  You also have to be careful the underlines don’t get WAY too close to the baseline, which is a big pet peeve for typography nerds.

Too Close!

The fix is to make sure your line-height and font-size values are set appropriately.  You can also detect problematic browsers and just not initialize the script for those browsers.  It’ll just degrade gracefully to what all linked text looked like before.


SmartUnderline, like UnderlineJS, has pretty much no documentation associated with it.  Well, for those wondering, here’s how to get it working on your project.

  1. Include smart-underline.js (or a minified version) on your page
  2. Run SmartUnderline.init({}) once the DOM has loaded

Simple enough.  Eventually, if there’s a Modernizer test for a text-decoration-skip property support, we’d wrap that init in an if(supports) statement.

Here’s where to download the project from GitHub.


UnderlineJS is, ironically, a lot smarter than SmartUnderline. It’s also a lot heavier.  It inserts and positions the HTML5 canvas element to create the descender-skipping underline.  Because it’s using the canvas element, the underlines are resolution-independent, and you can animate them.

Seriously!  Animated underlines!  Check out the demo and hover over the underlines.  They bend and snap back like guitar strings.  I have no idea how we might ever use that in a production environment, but it’s still super cool.

UnderlineJS also pays closer attention to the golden ratio, which SmartUnderline approximates.

UnderlineJS Golden Ratio

That said, the canvas element doesn’t respect letter-spacing.  The CSS tricks applied by SmartUnderline do.


UnderlineJS is also missing basic usage documentation.  In fact, the whole impetus for writing this post was a comment made on the project’s GitHub repo where someone asked us to write this.

So for @oyeanuj and the others, here’s how to use UnderlineJS in your project.

  1. Include js/baseline-ratio.js
  2. Include js/underline.js
  3. (Optional) include any of the add-on packages, like multiple-underline.js
  4. Yeah.  That’s it.  It’s self-initializing as far as we can tell.

Here’s where to download the project from GitHub.

SORRY: Quick apology for the confusion in this GitHub issue thread.  We provided instructions for SmartUnderline there, not UnderlineJS.  Oops. We posted the correction.

Which One?

As we were rebuilding our website for JDM Digital’s 10 anniversary, we played around with both descender-skipping javascript libraries.  In the end, we went with SmartUnderline for the following reasons:

  • Not self-initializing so we could turn it off for problematic browsers
  • It actually parses the external CSS to see if we wanted that text underlined in the first place
  • Is supported by more browsers since it’s basically just applying some CSS tricks dynamically
  • Respects letter-spacing
  • Is much lighter-weight (less expensive on performance)

JDM Underlines

Learn more about that project, code-named: JDM10.

A Plea to the W3C

Both javascript libraries are trying to do the same thing, for the same reasons.  At this point, neither look to be actively maintained and they’re both really experimental–trying to push the boundaries of web typography.

@wentin, the developer behind UnderlineJS, makes the following motion to the W3C for these new CSS rules to be included in CSS4.

text-underline-color: #000000;
// auto means the same color as the text color, or hex value

text-underline-position: auto;
// could be ratio or px or auto

text-underline-skip: true;
// true to set holes around descenders, false to turn it off

text-underline-width: auto;
// could be auto or px or ratio

We second that motion and we were pleasantly surprised to see the text-underline-skip property is now a “candidate,” according to Mozilla Developers.

Maybe there will come a day we can all see beautiful text underlines on the web.  Until then, we’ll just keep struggling.

A design professor of mine once told me, “Never let your tools restrain your creativity.”  I might rephrase that to, “If your tools are getting in the way of your creativity, search GitHub for better tools.”

Share the love:


Your Thoughts?

Your email address will not be published. Required fields are marked *


Get the Email

Join 1000+ other subscribers. Only 1 digest email per month. We'll never share your address. Unsubscribe anytime. It won't hurt our feelings (much).

Preview Email