Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-display][css-pseudo] Interaction of display:contents and ::first-line #1310

Open
Loirooriol opened this issue Apr 29, 2017 · 14 comments
Open
Labels
css-pseudo-4 Current Work

Comments

@Loirooriol
Copy link
Contributor

Loirooriol commented Apr 29, 2017

Typically, inheritance follows the element tree. However, the ::first-line is able to "hijack" the inheritance of some properties:

During CSS inheritance, the portion of a child element that occurs on the first line only inherits properties applicable to the ::first-line pseudo-element from the ::first-line pseudo-element.

The problem is that the place in which ::first-line is generated depends on the box tree, and display: contents generates no boxes, so I'm not sure how they interact.

The implementations of display: contents (Firefox and Chrome) are not interoperable, and both seem undesirable:

  • On Firefox, inline contents in the first line are not affected by ::first-line if they are inside an element with display: contents. They inherit directly from that element instead. Example. Bug 1305951
  • On Chrome, the mere existence of ::first-line prevents inline contents in the first line from inheriting from a display: contents parent. They inherit first from ::first-line, and then from the nearest non-display: contents ancestor. Example. Bug 706316

For example, https://jsfiddle.net/0q8paowL/

main::first-line { color: blue; text-decoration: underline; }
div { display: contents; color: green; letter-spacing: 10px; }
span { display: contents; color: red; }
<main>
  <div>aaa <span>bbb</span> <p>ccc</p></div>
</main>

I will attempt to represent the inheritance using a fictional tag sequence, which I'm not sure is right because ::first-line only exists in the box tree and display: contents in the element tree.

I see three reasonable possibilities:

  • Place the ::first-line as outermost as possible, breaking display: contents elements if necessary:

    <main>
      <main::first-line>
        <div no-box>aaa <span no-box>bbb</span></div>
      </main::first-line>
      <div><p>ccc</p></div>
    </main>

    Then aaa would be green (from div) and bbb would be red (from span). Both would inherit letter-spacing (from div). This would be closer to what Firefox does, but they would also receive a blue underline from ::first-line.

  • Nest ::first-line inside display: contents elements, breaking it if necessary:

    <main>
      <div no-box>
        <main::first-line>aaa</main::first-line>
        <span no-box><main::first-line>bbb</main::first-line></span>
        <p>ccc</p>
      </div>
    </main>

    Then aaa would be blue (from ::first-line) and bbb would be blue (from ::first-line). Both would have blue underline (from ::first-line). This would be closer to what Chrome does, but they would also inherit letter-spacing (from div).

  • Let ::first-line enclose display: contents elements that only have inline contents, but nest it inside display: contents elements that have some block-level.

    <main>
      <div no-box>
        <main::first-line>aaa <span no-box>bbb</span></main::first-line>
        <p>ccc</p>
      </div>
    </main>

    Then aaa would be blue (from ::first-line) and bbb would be red (from span). Both would have blue underline (from ::first-line) and letter-spacing (from div). This would be like a mix of the previous possibilities.

@Loirooriol
Copy link
Contributor Author

I think the first option makes more sense, because the others may need to break ::first-line, which until now I think it was never necessary. And display: contents seems more inliney than blocky to me, so nesting it inside ::first-line makes sense. This is also the behavior which would result from the alternative definition of display: contents that I proposed in #1313.

@fantasai fantasai added css-display-3 Current Work css-pseudo-4 Current Work labels May 2, 2017
@tabatkins
Copy link
Member

Firefox is, as far as I can tell, broken in general for ::first-line on an ancestor. In particular, the following:

<!DOCTYPE html>
<style>
main::first-line { color: blue; text-decoration: underline; }
div { color: green; letter-spacing: 10px; }
span { color: red; }
</style>
<main>
  <div>aaa <span>bbb</span> <p>ccc</p></div>
</main>

displays "aaa" in green, and nothing with any underlines, at least in v53.

@Loirooriol
Copy link
Contributor Author

Yes, that's bug 317081.

@tabatkins
Copy link
Member

Yes, @fantasai and I think that the first option is best. #2 is bad because it produces sibling ::first-line boxes, which doesn't happen currently and would break certain types of formatting, such as image backgrounds and letter-spacing.

#3 is bad because it's actually impossible - the boxes don't exist, so we don't know whether they "would contain" inlines or blocks (that fact can change depending on surroundings). Also, appending content to an element shouldn't fundamentally change the structure of earlier contents.

So #1 is the most reasonable, I think - just look at the resulting box tree and insert ::first-line boxes as appropriate. This keeps ::first-line generation purely a box-tree-time operation (which both #2 and #3 fail, since they require element-tree information) The only downside is that, from an author's perspective, it "flips" inheritance for text inside a display:contents that would have been a block (without display:contents, the ::first-line goes inside the div, so text inherits from the ::first-line rather than the div), however we don't really have a concept of "would have been a block" (as the block-ness comes from the display value).

@tabatkins
Copy link
Member

AKA this bug depends on #1118 getting fixed first.

@Loirooriol
Copy link
Contributor Author

Now I'm thinking that option 1 may be a bit more costly to implement, e.g. if you have

<section>
  <div ><div ><div ><div ><div ><div ><div ><div ><div ><div >
    <span>Foo</span>
  </div></div></div></div></div></div></div></div></div></div>
</section>
section::first-line { color: green }
div { display: contents }

When the browser generates the styles for the section, it sees a ::first-line must be generated, but does not know where. I guess it must first iterate all the nested div because there could be some block container inside them. When it finds out that nope, then it goes back and creates a style for the outermost div which inherits from section::first-line, then a style for the second div which inherits from the previous style, and so on. Alternatively it could start creating these styles once it sees the first display: contents element, but if there were a block container inside, that work would have been useless.

Option 2 seems easier to implement: once you find a first-child inline-level inside a block container, create a ::first-line fragment, let it inherit from the parent element of the inline, and place the inline-level (and following inline-level siblings, until the end of the line) inside that ::first-line.

@fantasai
Copy link
Collaborator

fantasai commented Jul 5, 2017

CC @bzbarsky

@bzbarsky
Copy link

I don't see why the scenario described in #1310 (comment) is really a problem any more so than it would be if all the <div>s were display:inline.

Past that:

  1. I wish the CSS WG would stop introducing features if they have not actually through through their interactions with all the features they have introduced. The burden should be to prove that a new feature is compatible with all existing ones before it's added, not to discover during implementation that things are incompatible with each other.

  2. I haven't really thought about how all this should interact with the multiple first-lines thing that CSS specifies (and no one actually implements in practice, at least not as specified). As noted above, Gecko doesn't implement that, has no plans to implement it, and hence I don't have any good implementation experience or intuition about how it should work with display:contents.

  3. As noted, option 2 violates a current "there is at most one first-line box generated by a given selector for a given block" invariant which may lead to weirdness of all sorts. The background situation is particularly troubling.

@Loirooriol
Copy link
Contributor Author

@bzbarsky If the <div>s were display:inline, then their first fragments would inherit from section::first-line for sure. But with display:contents and option 1, you can't know if the pseudo-element will be placed outside or inside the <div>s until you check whether all child boxes are inline-level or there is some block-level.

That's how I see it, but I'm not an implementator, so I might be wrong or it might not be a big problem.

@bzbarsky
Copy link

then their first fragments would inherit from section::first-line for sure.

Sure, but then you still have to recursively change the styles on them going down the tree...

That said, what Gecko actually implements is done on the box tree; so for us option 2 would in fact be quite a bit easier to implement, but not because of the "have to look at them all" bit. Rather it's because it avoids the need to attach multiple styles to a single element (the display:contents thing), which is not something we have infrastructure for right now (we can attach styles to boxes, and one style to an element).

@bzbarsky
Copy link

That said, "quite a bit easier to implement" is still "pretty annoying to implement", since it would change other invariants...

@css-meeting-bot
Copy link
Member

The Working Group just discussed Interaction of 'display: contents' and ::first-line, and agreed to the following:

  • RESOLVED: defer to css-pseudo-4 to address as part of more rigorously defining ::first-line cascading/inheritance.
The full IRC log of that discussion <dael> Topic: Interaction of 'display: contents' and ::first-line
<dael> github: https://github.com//issues/1310
<dael> fantasai: Proposal is defer to pseudo spec
<dael> Rossen: I support it
<dael> dbaron: Flip is display contents is new and ::first-line has been around since css 1
<dael> Rossen: Then it's easier to spec in first-line
<rachelandrew> re previous issue ED of multicol says "A multi-column container establishes a new block formatting context, as per CSS 2.1 section 9.4.1."
<dael> dbaron: I don't htink that's true. I proposed in the past removing first-line and first-letter...they're very complex
<dael> fantasai: Part of the issue is inheritence and cascade of first-line and that's underspec. I think solving here means we have to solve in pseudo first so it makes sense to solve together.
<dael> fantasai: Either way both features are impl. It's a question of which spec do we tackle in.
<dael> tantek: Impl with scare quotes. I'd be interested in seeing any interop tests
<Rossen> rachelandrew, right, the BFC part is understood, the inner display value is what will be interesting to define... since it's not really a flow-root
<dael> fantasai: It's impl for other things, jsut not this combo of things
<dael> florian: Regardless of history, fantasai point there's a dependency means we can push it there or be stuck. We can't just define in display. So I support the proposal
<dael> Rossen: Objections to defer to css-pseudo-4 to address as part of more rigorously defining ::first-line cascading/inheritance.
<dael> tantek: Which spec depends on which?
<dael> fantasai: Defining interaction of display contents and first-line is both. display-contents has no open issues. first-line has "someone please define inheritence" and defining how they combine requires that.
<dael> fantasai: Proposal is defer the interaction definition to pseudo spec so that it can hold until inheritence is defined better
<rachelandrew> there's no other mention - was trying to find the issue florian mentioned - which I think is this one https://github.com//pull/1588
<Rossen> who is talking?
<dael> emilio: I would say claim first-line and display:contents is [missed] I think we need to define first-line earlier because if people want features that mess with layout modal
<dael> emilio: I think if we want to start definiting more complex features that mess with layout modal we should define these things earlier rather then later.
<dael> Rossen: I sympathize. Only ocunter argument is that for the more complex features/layout systems it's not uncommon that we would push other horizontal features to the specific areas so that they define their own extension rather then trying to lump into one spec.
<dael> Rossen: In this case I'm inclined to push complexity of display:contents to ::first-line into pseudo because it will take longer to define and no reason to hold back display:contents for first-line
<dael> emilio: Agree, but shouldn't defer defining infinitely
<dael> Rossen: Agree. If you have time to work on that people would support it
<dael> emilio: Fair enough
<dael> Rossen: Other opinions about this? If not we can try and resolve
<emilio> myles: sorry about that, hopefully it's better now?
<dael> tantek: Only other thing...to make interaction a CR blocker. I'm fine witht he proposal if we define that defining it blocks CR
<dael> fantasai: Not okay
<dael> Rossen: Why is that the case?
<dael> tantek: If you've impl ::first-line then the interaction is a new thing introduced by this spec and therefore must be defined or it's an outstanding issue which we're not to have when enter CR
<dael> florian: Assuming that other then display:content ::first-line was well defined I'd agree. But it's not so I don't.
<fantasai> +1 to florian
<dael> emilio: Yeah I think the...
<dael> tantek: Weither or not it's well defined adding another thing makes it worse. We have to force resolution
<emilio> I think the undefinedness is on ::first-line
<dael> fantasai: It'll be forced when trying to move pseudo to CR. It's on the to do list.
<dael> Rossen: tantek your point is on the record. We're not close to CR. Once we're close we'll try and untangle
<dael> tantek: I'm worried about another semi-broken feature but I accept your approach
<fantasai> tantek, it's already introduced, so putting it in CR is just doing our best to document reality
<dael> Rossen: Objections?
<dael> RESOLVED: defer to css-pseudo-4 to address as part of more rigorously defining ::first-line cascading/inheritance.

@fantasai
Copy link
Collaborator

@Loirooriol I think the spec at this point would be implying your option 1, more or less. Do you see anything that needs further clarification, or should we close the issue?

@Loirooriol
Copy link
Contributor Author

@fantasai I don't see where the spec implies option 1. It still seems unclear to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-pseudo-4 Current Work
Projects
None yet
Development

No branches or pull requests

5 participants