Skip to content

[css-display] Should anonymous boxes always inherit through the box tree? #1118

Closed

Description

@Loirooriol

CSS Display says

anonymous boxes (which only exist in the box tree) inherit through their box tree parentage

I think this implies an anonymous box doesn't inherit from its parent element if the parent has display: contents, because that means

The element itself does not generate any boxes

For example,

<section>
  <div>Foo</div>
</section>
section {
  color: red;
}
div {
  color: green;
  display: contents;
}

Foo is wrapped inside an anonymous inline box, so according to the quote above, it should inherit the red color from its parent box, which is the box of the section, because the div does not generate boxes.

But this seems wrong, because if we had

<section>
  <div><span>Foo</span></div>
</section>

then the span would inherit the green color from the div through the element tree.

In Firefox and Chromium the text in the first example is green as expected, I think it's just that the spec is confusing.

Activity

  1. changed the title [-][css-display] Should anonymous boxes really inherit through the box tree?[/-] [+][css-display] Should anonymous boxes always inherit through the box tree?[/+] on Mar 23, 2017
  2. FremyCompany commented on Apr 12, 2017

    @FremyCompany
    Contributor

    Can we add a test case here?

  3. tabatkins commented on Apr 12, 2017

    @tabatkins
    Member

    Yeah, I think that terminology is wrong now. We should probably define, for each anonymous box, what its "originating element" is, same as pseudo-elements have, which determines what it inherits from.

  4. css-meeting-bot commented on Apr 19, 2017

    @css-meeting-bot
    Member

    The CSS Working Group just discussed Should anonymous boxes always inherit through the box tree?.

    The full IRC log of that discussion
    <astearns> topic: Should anonymous boxes always inherit through the box tree?
    <astearns> github topic: https://github.com/w3c/csswg-drafts/issues/1118
    <myles> fantasai: There are anonymous boxes in the box tree. We defined an anonymous box in the box tree has initial values except for the ones which are inherited (from its parent box in the box tree). But! When we have display:contents, if the parent of the anonymous box, then the element's parent is really its grandparent!
    <myles> TabAtkins: "parent box" is reasonably well-defined now, but with display:contents, not so much
    <myles> fantasai: what I expect is that we look at the parent box in the box tree and we look at the element which generated that box
    <myles> fantasai: However, implementations don't look at the box tree, they look at the parent element and its properties.
    <myles> fantasai: sooooooo this is busted
    <TabAtkins> (Specifically, "parent box" is simple enough, in a pre-display:contents world, that we don't have to worry much about the fact that it's weakly defined. With display:contents, tho, the full box tree starts being more relevant, adn the weak definition si more troublesome.)
    <myles> fantasai: so are these bugs? Or should we update the spec?
    <myles> TabAtkins: we should do the latter. Inheritance doesn't pay attention to the box tree. The fact that this uses the box tree was hand-wavey
    <myles> TabAtkins: <gives obscure example>
    <fantasai> <section> <div>Foo</div>
    <fantasai> </section>
    <fantasai> <section> <div><span>Foo</span></div>
    <fantasai> </section>
    <fantasai> section { color: red;
    <fantasai> }
    <fantasai> div { color: green; display: contents;
    <fantasai> }
    <myles> TabAtkins: explains the example
    <myles> dbaron: there are 2 different distinctions to make (but one may not be observable)
    <myles> dbaron: gecko recently changed how how anonymous boxes inherit (but only for nested anonymous boxes). Previously, if you have 2 nested ones, one would inherit from the other. Now, all nested boxes inherit from the closest real element.
    <myles> Florian: is there an observable difference?
    <myles> dbaron: not to regular users
    <dbaron> xidorn: what about a writing-mode change on an element with display:contents and text inside it?
    <myles> astearns: we need to change the spec to match the implementations
    <myles> fantasai: if you have an inline element and its the child of a block, then it's the child of the root inline of that block. If you remove that inline element, then the contents of that inline element (the text) becomes a child of the block's root inline. There's no intervening box belonging specifically to the text. Now, if we make that box go away, there's nothing that is holding the properties that apply to the text other than the root inline. The root inline'
    <myles> properties apply tot he text because there's nothing between there.
    <myles> fantasai: if you put an inline in between the text and the root inline, give it a property, then pull it away with display:contents, then it's not in the formatting tree. How is it contributing a color when it's gone?
    <myles> TabAtkins: inheritance always follow the element tree
    <myles> TabAtkins: text doesn't have properties, but it does know things like color
    <myles> fantasai: we have to invent this idea of a text frame, and say that it has properties, and it's an anonymous object which you can't get rid of
    <myles> TabAtkins: we kind of had to do that with selectors already.
    <myles> TabAtkins: we say that clicking on raw text correctly triggers, even when there are intervening shadows & etc.
    <myles> fantasai: it is already a thing, but it doesn't have properties. Now we are saying that it has its own properties.
    <myles> TabAtkins: yes, to achieve what all implementations do and what makes sense
    <myles> TabAtkins: display:contents shouldn't change inheritance
    <myles> fantasai: background color doesn't go away when you take away the box
    <myles> TabAtkins: in the example in the issue, do you think in the first bit that text should be red?
    <myles> TabAtkins: where red is assigned to <section> and green is assigned to <div>
    <myles> fantasai: reads really hard
    <myles> fantasai: i expected div of to take the color of the section, and div span foo to take the color of the div.
    <myles> TabAtkins: i disagree.
    <myles> TabAtkins: i agree with the originator and what implementations do
    <myles> TabAtkins: we can work through the implementations to make things well-defined
    <myles> astearns: this will be difficult to specify.
    <myles> fantasai: it requires inventing a new type of box in the inline layout model which we don't' have yet.
    <myles> TabAtkins: putting the span in there changes how inheritance works, which changes what users see, and this is unreasonable. The present of an element shouldn't make the color jump over the div.
    <myles> Florian: the consequences that a non-styled span changes things is scary.
    <myles> astearns: let's table this.
    <myles> fantasai: If we make a new box, it belongs in the inline layout module, not this module
    <myles> TabAtkins: let's put all the boxes in display:
    <myles> fantasai: but you can't create it with display:
    <myles> fantasai: TabAtkins: <tries to figure out which modules this should go in>
    <myles> astearns: please stop
    
  5. tabatkins commented on Apr 19, 2017

    @tabatkins
    Member

    fantasai and I seem to disagree on the behavior - she think the first example should have red text; i find it vaguely horrifying that inserting a non-styled span should have dramatic effects on inheritance in this sole instance.

    Assuming we go with "everything should be green", doing this rigorously seems to require us to define "text" as an object in the element tree that has properties (only set via inheritance), and which generates "text" in the box tree accordingly. I'm down with this.

    (Alternately, we can do some handwavey "the element that would generate the text's parent box, if it wasn't display:contents". But that's handwavey and nasty; I'd much prefer to get a better, more rigorous description of text in the CSS model.)

  6. FremyCompany commented on Apr 19, 2017

    @FremyCompany
    Contributor

    Wouldn't it be unfortunate if

    <hgroup>
      <h1>Introduction</h1>
      <p>...
    </hgroup>
    
    h1::before { content: "Chapter " counter(h1) ": "; }
    

    would result in "Chapter 1: " and "Introduction" having different colors?

  7. bzbarsky commented on Apr 19, 2017

    @bzbarsky

    define "text" as an object in the element tree that has properties (only set via inheritance), and which generates "text" in the box tree accordingly

    For what it's worth, this is what Gecko does anyway. I can't speak for other implementations.

  8. Loirooriol commented on Apr 20, 2017

    @Loirooriol
    ContributorAuthor

    Introducing text boxes would need to rewrite inline layout algorithm in order to take them into account. As I said in #1249 (comment), I think it would be easier (both conceptually and to spec) to handle this by wrapping each contiguous run of text that is directly contained inside an element into an anonymous inline box, which would inherit from the element. In practice it should almost be the same. Thoughts?

  9. astearns commented on May 2, 2017

    @astearns
    Member

    I believe the next step is for @tabatkins to come up with a proposal, so I'm removing the agenda+ waiting for that.

  10. tabatkins commented on May 15, 2017

    @tabatkins
    Member

    Proposed changes:

    • Display - Define that the element tree contains text as well as elements.

    • Cascade - Define how inheritance works over text

    • Scoping - Rigorously define how text moves around due to shadows

    • Text - Maybe some minor changes to rigorously talk about text?

    • Text Decor - clarify whether the magic decoration inheritance is thru the box tree or element tree

    • maybe more?

    @fantasai and I are gonna explore what the actual edits need to be before we present this to the WG.

  11. 20 remaining items

  12. tabatkins commented on Jun 5, 2017

    @tabatkins
    Member

    Obviously it wouldn't be surprising at all if there were an explicit rule targeting the span and setting the color.

    Yes, that would of course be normal and expected. As far as I can tell that's not germane to this issue, tho? Again, the issue is that, without something like what's described here, the inheritance behavior of text depends on whether or not its immediate parent element generates a box. This is inconsistent with how inheritance works for elements, thus the surprise.

    I'm arguing that being styled via inheritance from a display:contents element is no more surprising and the resulting behavior does not necessarily warrant introducing the entirely new concept of "text node styles".

    I'm very confused by this statement. You're correct that being styled via inheritance from a display:contents element isn't surprising. That's what we're trying to ensure will happen! Right now, as vaguely written, text won't inherit from a display:contents parent element; our concept of "text nodes" carrying styles ensures that it does, like normal elements do.


    To help alleviate my confusion about what position you're advocating for, @anttijk, can you quickly say what color you expect the text to be in the two examples in the first comment?

  13. anttijk commented on Jun 6, 2017

    @anttijk

    This is inconsistent with how inheritance works for elements, thus the surprise.

    We didn't have a case where you could have non-box-generating element with visible text children before display:contents. There is nothing to be inconsistent with; the case is new. It seem that the simplest solution would be that the text properties are defined by the parent box (which is also the specced behavior before the proposed changes here).

    I'm very confused by this statement. You're correct that being styled via inheritance from a display:contents element isn't surprising. That's what we're trying to ensure will happen! Right now, as vaguely written, text won't inherit from a display:contents parent element; our concept of "text nodes" carrying styles ensures that it does, like normal elements do.

    I don't find it particularly surprising that a non-box generating element doesn't affect child text node style. In fact that's what I would expect. The text node is behaving as if it was a direct child of the box-generating ancestor, something that is easily explained.

    Perhaps there is some better example than has been presented here so far why this is a bad or inconsistent behavior? The argument in the original post is that it is surprising that an unstyled element is still being affected via inheritance. I was curious why people found it surprising.

  14. tabatkins commented on Jun 6, 2017

    @tabatkins
    Member

    We didn't have a case where you could have non-box-generating element with visible text children before display:contents. There is nothing to be inconsistent with; the case is new.

    Of course the case is new. But before display:contents, "text nodes exists in the element tree, and inherit from their parent element" and "text exists in the box tree, and inherits from its parent box" were indistinguishable. Both behaviors had exactly the same effect (none of the box-tree manipulations that existed prior to display:contents changed the parent box of text in a way that would change the inheritance results).

    Thus, you could pretend that inheritance always worked thru the element tree, for all styling. Now, we suddenly have a case that breaks the symmetry, and we have to decide whether we prefer "inheritance always goes thru the element tree" or "inheritance is thru the element tree for elements, and thru the box tree for text". The former is simpler overall, but requires introducing some new concepts to CSS; the latter requires no new spec concepts, but introduces an asymmetry and results that at least some people find surprising.

    Neither way is particularly difficult for implementations, as far as I can tell, and thus I strongly prefer the one that doesn't produce a behavior asymmetry.

    The argument in the original post is that it is surprising that an unstyled element is still being affected via inheritance. I was curious why people found it surprising.

    No, you seem to be misunderstanding the example? It's pointing out the difference in the style of text; the span is used to introduce the styling difference, it's not the point of the example.

    The argument in the example is that it would be surprising if the two target elements in the markup below ended up with different color values:

    <parent color:red>
      <child display:contents color:green>
        <target />
      </child>
    </parent>
    <parent color:red>
      <child display:contents color:green>
        <wrapper>
          <target />
        </wrapper>
      </child>
    </parent>

    In both examples, target should have a computed color of green: in the first example, target directly inherits it from child; in the second example, target inherits from wrapper, but wrapper just inherits it from child, so it should be green as well. (This is standard, non-controversial CSS.)

    It's weird, then, that if you replace <target /> with raw text, you'd get a different result - it would be red in the first example, and green in the second. What's the justification for raw text acting differently here? Why, if I add a meaningless wrapper element that doesn't interfere with inheritance at all (for scripting purposes, perhaps), do I get a dramatic difference in inherited value?

    Our diff fixes the specs so that this all works consistently, whether it's an element or text.

  15. anttijk commented on Jun 8, 2017

    @anttijk

    @tabatkins Thank you for restating the basic facts of the case. The actual argument seems to boil down to a personal preference.

    I don't think we should abandon the "only elements and pseudo-elements have style" invariant for this. It is valuable in explaining and understanding how CSS works. That this requires little or no spec changes is a bonus.

    I'm opposed to making these changes. CSSWG should just clarify that text style is determined by the box tree (if it is currently unclear).

    No, you seem to be misunderstanding the example?

    I understand the example perfectly and already explained why I don't find the behavior surprising at all.

  16. frivoal commented on Jun 8, 2017

    @frivoal
    Collaborator

    I don't think we should abandon the "only elements and pseudo-elements have style" invariant for this.

    This seems less important than the "adding a non styled span in the middle inline content has no effect on rendering" invariant. If we could keep both, that'd be great. But as it seems we cannot, this one seems more important to preserve.

  17. anttijk commented on Jun 8, 2017

    @anttijk

    @frivoal There is no such thing as "non-styled span" in a rendered document. In this case the span is getting styled via inheritance which I find no more surprising than being styled by explicit "span { color:green }".

  18. frivoal commented on Jun 8, 2017

    @frivoal
    Collaborator

    @anttijk I meant a span on which there is no specified styles.

  19. fantasai commented on Jul 5, 2017

    @fantasai
    Collaborator

    @anttijk It is a general principle here that a bit of text and a <span>bit</span> of text, where <span> has no style rule applying to it, render identically. This invariant is more important than any intuition about how things should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions