:first-letter is weird

Ross Angus
4 min readApr 1, 2019
This was the old way of doing first-letter. A lot of mead was involved.

:first-letter's an ancient pseudo-element, which has excellent modern support. It can be used to add a drop-capital to paragraphs, like this. You're probably looking at it and thinking “this is another pseudo-element, right? Cool. I know how to use this. I've tinkered with :before and :after.”

Perhaps I’m projecting, because that’s exactly what I thought last week. I was wrong. Please, allow me to share what I’ve learned (I’ve created examples of all of these on this codepen).

It’s more of a selector, than an element

The :first-letter selector finds the first character within an element, then applies certain styles to it. That even applies if you set a content string on that element. Here's an example:

p:before {
content: "This is the before. ";
}
p:first-letter {
border: solid 1px red;
}

If the paragraph looks like this:

<p>I am a paragraph</p>

… then the red border will be around the “T” of “This is the before”, rather than the “I” of “I am a paragraph”. This will also happen if the content is declared later in the code than the :before element.

How a browser chooses what the :first-letter is.

What if the content property is empty?

You can have a content declaration on a :before which is an empty pair of quotes:

p:before {
content: "";
border: solid 10px green;
}
p:first-letter {
border: solid 1px navy;
}

As you might expect, the :first-letter style will skip past it, onto the first character of the paragraph. However, as soon as you make the :before pseudo-element display: block, the first-letter fails to find a match. It doesn't match the :before element or the first character of the paragraph.

This is because the first letter must occur on the first line of the containing paragraph. As soon as the :before element becomes block, it forces the following text onto a new line, so there's no longer a :first-letter to find.

Can you stack elements?

What if you had a :first-letter and an :after element on the same paragraph, and you tried to stack them?

Their natural order would be :after on top, as it appears second in the markup. But can you reverse this?

The answer is no — position relative or absolute has no effect on the :first-letter element. And as a result, it doesn't matter what you set the z-index of either element to (well, you could set the z-index of the :after to -1, I suppose, but this would put it behind the whole paragraph, not just the :first-letter)

Can you make it block?

No. :first-letter will take no other display property other than inline - not even inline-block. This means that it will ignore any width property applied to it.

Can you use outline?

No. :first-letter will not take an outline style. This is nothing to do with it being display: inline - inline elements can still have outline applied to them. For whatever reason, outline wasn't on the list of permitted properties (see below).

What does the specification say?

Perhaps I should have visited the spec before I did all my experiments and wrote this up. The W3C wiki lists all the properties which you can apply to :first-letter:

  • font properties
  • text-decoration
  • text-transform
  • letter-spacing
  • word-spacing
  • line-height
  • float
  • vertical-align (only if float is none)
  • margin properties
  • padding properties
  • border properties
  • color property
  • background properties

In addition, an article on CSS Tricks points out that :first-letter can only apply to the first character of a block level element. So you can't use it to give an anchor tag a wee boost, for example (this might be possible, but you'd need to change the display property of the anchor first).

When I was experimenting with :first-letter, the properties which would work, and those which would not felt rather arbitrary. But the more I experimented the more it made sense: when you use :first-letter, you aren't creating a new element in the DOM, you're just selecting whatever the character is at a particular position on the page. What's more, using the pseudo-class doesn't change its relationship with the rest of the paragraph. It remains firmly embedded inside that paragraph. The most you can do to change the flow of the paragraph is to float the :first-letter to the right or left.

--

--

Ross Angus

The views I express here are mine alone and do not necessarily reflect the views of my employer.