DEV Community

Cover image for Why is CSS ::first-letter not working?
Salma Alam-Naylor
Salma Alam-Naylor

Posted on • Originally published at whitep4nth3r.com

Why is CSS ::first-letter not working?

I recently had a use for the CSS ::first-letter pseudo element. I was dealing with some inconsistently formatted strings from the back end, and wanted to make sure that on the front end, all strings were shown with lowercase letters except for the first, which needed to be uppercase. I thought it would be trivial to use the following CSS:

.parentElement {
  text-transform: lowercase;
}

.parentElement::first-letter {
  text-transform: uppercase;
}
Enter fullscreen mode Exit fullscreen mode

In my case, however, the first letter was not being uppercased, and I was confused about why. Here is a modified version of the HTML I was attempting to style:

<div class="parentElement">
  <div class="child1">
    <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
      <path>...</path>
    </svg>
  </div>
  <span class="child2">
    inconsistently FormattED string
  </span>
</div>
Enter fullscreen mode Exit fullscreen mode

Naïvely, I thought I would be able to apply the styles on the div with the class parentElement, and the styles would cascade down to the span with the class child2. However, it turns out that the ::first-letter pseudo element selector can only target text under a certain set of conditions.

The ::first-letter spec

The ::first-letter CSS pseudo-element applies styles to the first letter of the first line of a block container, but only when not preceded by other content (such as images or inline tables).

When drilling down into what exactly defines a “block container”, there is definitely some ambiguity across the CSS spec: “In specifications, block boxes, block-level boxes, and block containers are all referred to as block boxes in certain places. These things are somewhat different and the term block box should only be used if there is no ambiguity.” I won’t go deep into the specifics of block boxes and block containers in this post, but I will attempt to provide a summary:

An element is a block container only if it contains block-level or inline-level boxes. The following values for the CSS display property produce block containers:

  • block
  • inline-block
  • list-item
  • table-cell
  • table-caption
  • flow-root
  • inline (on one condition: inline elements become block containers when they contain inline text! The spec is difficult to read but I think I got the gist.)

The following values for the CSS display property produce block-level boxes, but not block containers, given how their child elements are formatted:

  • flex
  • grid

The key issue in my case was that I was attempting to target a non-block container; the parentElement class specified a display property of flex and attempting to cascade the styles for ::first-letter down to a child element.

The rules of ::first-letter

To summarise, using CSS ::first-letter will not work in the following conditions:

  • The element you are targeting is set to display: flex or display: grid
  • The element you are targeting is preceded by other content, such as a ::before pseudo element, images or inline tables
  • You are attempting to cascade ::first-letter styles from a parent element, even if the elements are block containers

To make sure CSS ::first-letter works for you:

  • Apply the ::first-letter styles directly to a block container (and those block containers are specified above)
  • Ensure the content you are attempting to target is not preceded by other content, such as a ::before pseudo element, images or inline tables

A note on browser support

CSS ::first-letter may have limited browser support: caniuse.com reports this pseudo element selector is not supported in Firefox, but Baseline reports that "This feature is well established and works across many devices and browser versions. It’s been available across browsers since ⁨July 2015⁩."

Using ::first-letter in action

To better understand how ::first-letter works, I threw together some examples of when this pseudo element can be correctly targeted, and when it fails to work. You can view the examples at CSS first-letter demo, and you can view the code here.

Top comments (6)

Collapse
 
anik_sikder_313 profile image
Anik Sikder

Really helpful breakdown. I used to think ::first-letter would just cascade like any other style, but your explanation about block containers and layout context cleared that up. Especially the flex/grid limitation, easy to overlook. Thanks for making the spec feel less cryptic.

Collapse
 
gamelord2011 profile image
Reid Burton

What browser are you using?

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor

I'm using Arc (Chromium), why?

Collapse
 
gamelord2011 profile image
Reid Burton

Some of the weirder browsers in the realm of arc can get... tempermental... when it comes to more recent css standards, is should work in Chromium.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.