CSS Text underlining too long when letter-spacing is applied?

It’s not perfect, but the best solution I have come up with so far is to mask it with a :after pseudo element. This way there’s no need for extra elements throughout your text.

For example:

h1 {
  /* A nice big spacing so you can see the effect */
  letter-spacing: 1em;
  /* we need relative positioning here so our pseudo element stays within h1's box */
  position: relative;
  /* centring text throws up another issue, which we'll address in a moment */
  text-align: center;
  /* the underline */
  text-decoration: underline;
}

h1:after {
  /* absolute positioning keeps it within h1's relative positioned box, takes it out of the document flow and forces a block-style display */
  position: absolute;
  /* the same width as our letter-spacing property on the h1 element */
  width: 1em;
  /* we need to make sure our 'mask' is tall enough to hide the underline. For my own purpose 200% was enough, but you can play and see what suits you */
  height: 200%;
  /* set the background colour to the same as whatever the background colour is behind your element. I've used a red box here so you can see it on your page before you change the colour ;) */
  background-color: #990000;
  /* give the browser some text to render (if you're familiar with clearing floats like this, you should understand why this is important) */
  content: ".";
  /* hide the dynamic text you've just added off the screen somewhere */
  text-indent: -9999em;
  /* this is the magic part - pull the mask off the left and hide the underline beneath */
  margin-left: -1em;
}

<h1>My letter-spaced, underlined element!</h1>

And that’s it!

You can also use borders if you want finer control over colour, positioning, etc but these require you to add a span element unless you have a fixed width.

For example, I’m currently working on a site which requires h3 elements to have 2px letter spacing, centred text and an underline with added space between the text and the underline. My css is as follows:

h3.location {
  letter-spacing: 2px;
  position: relative;
  text-align: center;
  font-variant: small-caps;
  font-weight: normal;
  margin-top: 50px;
}

h3.location span {
  padding-bottom: 2px;
  border-bottom: 1px #000000 solid;
}

h3.location:after {
  position: absolute;
  width: 2px;
  height: 200%;
  background-color: #f2f2f2;
  content: ".";
  text-indent: -9999em;
  margin-left: -2px;
}

and my HTML is:

<h3><span>Heading</span></h3>

Notes:

It’s not 100% pretty CSS but it does at least mean you don’t have to modify & hack your HTML to achieve the same result.

I haven’t yet had to try this on an element with a background image, so haven’t yet thought of a method of achieving this.

Centring text makes the browser display the text in the wrong place (it accounts for the text + extra spacing afterwards), so everything is pulled left. Adding a text-indent 0.5em (half the 1em letter spacing we used in the top example) directly on the h1 element (not the :after pseudo element) should fix this, though I’ve not tested this yet.

Any feedback is gratefully received!

Neal

Leave a Comment