41

CSS Scoping says

The descendants of a shadow host must not generate boxes in the formatting tree. Instead, the contents of the active shadow tree generate boxes as if they were the contents of the element instead.

CSS Pseudo-Elements describes ::before and ::after as

these pseudo-elements generate boxes as if they were immediate children of their originating element

So which of these is true?

  • First, all the contents of the shadow host (not including ::before and ::after) are replaced by the contents of the active shadow tree. And then, ::before and ::after generate boxes in the shadow host.
  • First, ::before and ::after generate boxes in the shadow host. And then, all the contents of the shadow host (including ::before and ::after) are replaced by the contents of the active shadow tree.

Firefox and Chrome do the former, but does the spec describe the behavior?

var root = document.querySelector('div').createShadowRoot();
root.innerHTML = "<p>Shadow content</p>";
div::before, div::after {
  content: 'Generated content';
}
<div>Content</div>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Did you take a look a the distribution algorithms of the Shadow DOM? If pseudo `::before` and `::after` elements can be considered as child nodes of the shadow host than this might describe the behavior. http://www.w3.org/TR/shadow-dom/#distribution-algorithms – DavidDomain Jun 28 '15 at 00:34
  • @DavidDomain Not much, I find that spec difficult to understand :S However, that spec seems to talk about what happens in the DOM, but `::before` and `::after` are not DOM nodes. – Oriol Jun 28 '15 at 00:48
  • Likewise i am having a hard time to follow along with the spec as well. I just thought maybe the Shadow DOM is designed that way to see pseudo elements as child nodes, but that is probably not the case and would not make much sense. – DavidDomain Jun 28 '15 at 01:00

2 Answers2

28

CSS Scoping spec author here.

The answer is actually, officially... undefined!

I didn't think about this interaction when I was writing the Scoping spec. I'll send an email to the list, and we'll figure it out. Almost certainly, we'll settle on whatever browsers currently do (which appears to be letting ::before/after work "as expected" even in shadow hosts).

Edit: The Working Group's response was unanimous - the current implementation behavior (::before/after do work on shadow hosts) is how it should be. I'll edit it into the Scoping spec shortly.

Xanthir
  • 18,065
  • 2
  • 31
  • 32
2

I think the key wording is in this part of the generated content section.

::before

Represents a styleable child pseudo-element immediately before the originating element’s actual content.

::after

Represents a styleable child pseudo-element immediately before the originating element’s actual content.

Excusing the obvious copy-paste error in the ::after description (it is a working draft), we can see that these pseudo-elements generate content outside, or "immediately before", the actual content of the element.

Compare this to this description from the Shadow Encapsulation section, it seems to confirm the behavior of Chrome and Firefox.

The descendants of a shadow host must not generate boxes in the formatting tree. Instead, the contents of the active shadow tree generate boxes as if they were the contents of the element instead.

In short, a shadow host replaces the actual contents of the element, and ::before and ::after generate pseudo-elements immediately before/after the elements actual content. Because the pseudo-elements create boxes outside the content being replaced, the content being replaced has no effect on the pseudo-elements.

Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
  • If I understand it correctly, your point is that ::before and ::after are like children but are not children. However, in [flexbox](http://www.w3.org/TR/css-flexbox-1/#flex-items) only in-flow children (and contiguous run of text) become flex items, but ::before and ::after become pseudo-elements. So that means they must be treated like if they were real children. – Oriol Jun 30 '15 at 01:25
  • @Oriol I'm not sure I follow. If my understanding is correct, the shadow host replaces the "content", but ::before/::after create separate boxes outside that content, "immediately before" (and after). The content being replaced has no effect on the pseudo-elements, because they are outside the content being replaced. – Alexander O'Mara Jun 30 '15 at 01:30
  • Yes, it seems that's what happens. However, pseudo-elements are not children but must behave like they were. And the children (and descendants) are replaced. But how can we know if that doesn't include pseudo-elements (because they are not real children), or if it does (because they behave like real children)? – Oriol Jun 30 '15 at 01:43
  • Does this work with ::-webkit-scrollbar ? I have been trying to add scrollbar of a ::part() but it isn't working when styling from outside the component – Nishant Oct 22 '21 at 12:40