Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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


Whenever letter-spacing is applied to something with an underline or a bottom border, it seems like the underline extends beyond the text on the right. Is there any way to do prevent the underline from extending beyond the last letter in the text?

For example:

<span style="letter-spacing: 1em; border-bottom: 1px solid black;">Test</span>

Perhaps it'd be possible with a fixed width <div> and a border, but that is really not an option to surround every underlined element.

Thanks!

like image 265
waffl Avatar asked Oct 25 '10 13:10

waffl


People also ask

How do you change underline length in CSS?

The text-underline-offset property in CSS sets the distance of text underlines from their initial position. Once you apply an underline for an element using text-decoration with the value of underline, you can say how far that line should be from your text using the text-underline-offset property.

How do I change the width of text underline?

You cannot modify the width of underline tag. Instead go for Border-bottom approach and change it's properties as required.

How do I increase the space between text and underline in HTML?

Instead of using the built-in text-decoration: underline; we are going to create our own underline using border-bottom-style property and then we can add padding-bottom to push it away as much amount we want. Example: We can increase the gap between the text and underlining using CSS.


3 Answers

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

like image 157
nealio82 Avatar answered Sep 17 '22 05:09

nealio82


The problem is that "letter-spacing" adds space by adding white space after each letter, but this space belongs to the letter, and thus the last one has an extra underline that makes it look like it's expanding beyond the last letter (if you select with the mouse the last letter of the div, you'll see what I mean).

You could solve it by having the last letter of the text block not having the "letter-spacing" property. For example:

<span style="letter-spacing: 1em; text-decoration: underline;">SPACEEE</span>
<span style="text-decoration: underline;">.</span>

It's far from ideal, but unless it's just a one line text (there, you could use a negative margin to the right), I can't think of any other solution.

like image 23
salgiza Avatar answered Sep 17 '22 05:09

salgiza


You can also use an absolute positioned pseudo element to achieve the underline, and counter the offset by specifying its with using the left and right property. Click below for an example.

<span style="letter-spacing: 5px; position: relative">My underlined text</span>

span:after {
    content: '';
    border-bottom:1px solid #000;
    display: block;
    position: absolute;
    right: 5px;
    left: 0;
}

https://codepen.io/orangehaze/pen/opdMoO

like image 33
Jason Robinson Avatar answered Sep 21 '22 05:09

Jason Robinson