HTML Question

In HTML, do ::after and ::before pseudoelements only work with renderable "non-replaced" elements?

I recently noticed on a project that the

pseudoelement did not add any content after an

input::after { content: "xxxxxxxxxx"; } // no "virtual last child" inserted into DOM "after" the input

(reference to "virtual last child" is from MDN page here)

Of course, an element such as a div will have content "after" it, and the last child "::after" will be inserted into the DOM:

div:empty::after { content: "xxxxxxxxxx"; }

//In DOM

but nothing is inserted in these cases:

head, script { content: "qaqaqa"; }

My initial assumption was that any HTML elements that are rendered by the browser with tags that should be closed (.e.g, p, body, html, div,....etc) will have
inserted as a last child (and
inserted as a first-child), whereas elements that do NOT fit this (e.g., script, head, img, br, input,...etc) will not exhibit this behavior. My CodePen attempts suggested this was correct.

I read through documentation which finally led me to this resource, in which a note reads:

Note. This specification does not fully define the interaction
of :before and :after with replaced elements (such as IMG in HTML).
This will be defined in more detail in a future specification.

(for definition of "replaced elements" see here)

So now my refined assumption regarding
is that these pseudoelements are only applicable to "renderable" elements which cannot be classified as "replaced elements" (Note this refined assumption now excludes
from use with
, whereas my initial assumption would have included it -
was tested with CodePen and no
last child is inserted into the DOM).

Would the refined assumption be correct?


HTML does not define which elements are replaced elements or which elements can contain ::before and ::after pseudo-elements. Neither do CSS2.1 or selectors-3. The latest rewrite of css-content-3, however, states pretty unambiguously:

Replaced elements do not have '::before' and '::after' pseudo-elements

although implementations of course are not consistent with the draft (famously or otherwise, WebKit/Blink) since this wasn't hitherto defined.

Whether an element can have ::before and ::after pseudo-elements is not defined by its content model (i.e. if it's void or otherwise), or whether it has an end tag, in HTML. And again, a lot of this is implementation-dependent. For example, some implementations allow br of all things to have ::before and ::after pseudo-elements, because nobody knows exactly how br is supposed to be implemented in terms of CSS and each browser does it its own way (because neither HTML nor CSS actually defines this).

A head element and any of its descendants can have ::before and ::after pseudo-elements — all you have to do is change their display to something other than none. Obviously, they're not supposed to be displayed, but that doesn't stop anyone trying to be clever.

As far as CSS is concerned, input and textarea are both considered replaced elements, even though textarea has a start tag, end tag, and content. Whether these elements should or must be replaced elements is not stated (not even in section 14.5 of WHATWG HTML), but most browsers render them as replaced elements by default, and this behavior usually can't be changed. And for the purposes of the ::before and ::after pseudo-elements not being supported, that's all that matters.