6

From the W3C standard's definition of pseudo-elements https://www.w3.org/TR/selectors-3/#pseudo-elements:

Pseudo-elements create abstractions about the document tree beyond those specified by the document language. For instance, document languages do not offer mechanisms to access the first letter or first line of an element’s content. Pseudo-elements allow authors to refer to this otherwise inaccessible information.

(My emphasis.)

Why excatly does the document language allow for detection of the first child element (so that :first-child is a css pseudo-class) but not of the first letter (so that ::first-letter is a css pseudo-element)? How should this "document language" be understood?

In essence the question is: Why is there a difference in picking the first element in contrast to the first letter? Why can the document language retrieve one but not the other?

I am not asking to the general difference between pseudo classes and pseudo elements, but rather I am asking specifically about why a first letter is conceptually different from a first child element. Other pseudo elements are less confusing: that ::after and ::before for example are pseudo elements is fairly obvious, as they relate to a "space" that isn't defined in the html structure. But the first letter is, so therefore the question of why such first letter is still treated differently.

Steeven
  • 4,057
  • 8
  • 38
  • 68
  • If you think that the top answer (or any further answers) to the marked dupe doesn't answer your question or if it raises further questions, please detail that in an edit to your answer and I'll be happy to re-open the question accordingly. – TylerH Feb 26 '19 at 16:16
  • @TylerH I don't really see this as a duplicate. I am aware of the difference between pseudo classes and pseudo elements, but am asking specifically about why a first letter is conceptually different from a first child element. Why `::after` and `::before` for example are pseudo elements is fairly obvious, as they relate to a "space" that isn't defined in the html structure. But the first letter *is*, thus my question. – Steeven Feb 27 '19 at 07:18
  • 2
    No, `::first-letter` isn't defined in the structure. In other words, you don't have tags wrapping around the first letter (unless you do, then you don't need `::first-letter`). That is what the difference between pseudo classes and pseudo elements is. If you can target it with a simple selector like a class or element selector, then it's not a pseudo element. You can't target the first letter with a simple selector because it's like trying to target a partial inner text fragment... CSS can't do that. This problem is called 'naked text' (be careful when googling that...) – TylerH Feb 27 '19 at 14:20

1 Answers1

5

The document language refers, in the most typical CSS use case, to HTML. The document tree (as referred to throughout Selectors) refers to the DOM tree that is constructed from the markup.

A pseudo-element is something that is generated based on an existing layout. That is, a layout must first be constructed and rendered based on CSS that's applied to elements in a DOM tree. This cannot be accomplished with the document language, the markup, alone.

You'll notice that the ::first-letter pseudo-element only applies to block container boxes, for example. There's no way to know whether an element (or its descendant) will have a ::first-letter pseudo-element until it's determined to be a block container box (the only kind of box that can directly contain a flow of inline content), and that is determined by CSS, not by HTML. As a more concrete example:

<p>Hello world!

By default, a p element is display: block. This results in a block box, which is a kind of block container box. But even so, this default is implemented using CSS. And if you were to override that default with the following CSS rule:

p {
  display: inline;
}

this element then becomes an inline box, and p::first-letter will no longer have any effect on it.

Intuitively, it still seems trivial to determine the first letter of an inline box compared to a block box (or any other type of box), but things get pretty complicated once you have several inline boxes in the same inline formatting context all interacting with one another.

::first-line is much more clear-cut: not only is it impossible to know how long the first formatted line of an element's text is until you format the line, but the contents and length of this line can also change as you resize and/or reflow the element and its contents.

In contrast, a tree-structural pseudo-class such as :first-child matches elements in the DOM independently of the layout. Without having to render anything, the browser can tell right off the bat which of the elements is the first child of its parent. All you need is the DOM tree of elements, which means all the information you need can be retrieved from the document language, the markup. For example, the first child of the ol in the following fragment is always the same no matter what CSS you apply to it:

<ol>
  <li>First
  <li>Second
  <li>Third
</ol>
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    I don't believe this fully answers the OP's question. You say the contents of `::first-line` change when the page is resized, but that's not the issue; many properties of the element itself and its children, like `clientHeight`, also change when the page resizes. So there's no difference there in principle. The OP (and me) wants to know why you can retrieve `querySelector(':first-child').clientHeight`, but not `querySelector('::first-line').clientHeight`, while both properties are known to the browser. The only difference being that the `::first-line` is not in the DOM. – Mr Lister Feb 26 '19 at 21:34
  • 2
    @Mr Lister: And the question asks why ::first-line is not in the DOM - to which the answer is that the DOM is a reflection of the markup, not the rendered layout. Not even the CSSOM provides a complete abstraction of the rendered layout. The layout is rendered *based on* both object models, not the other way around, and pseudo-elements in turn generated based on this rendered layout. – BoltClock Feb 27 '19 at 05:55