w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.44k stars 657 forks source link

[css-page-3] clarification on whether "page" applies to (and propagates up from) "only-child" block-level elements #7235

Open dholbert opened 2 years ago

dholbert commented 2 years ago

In css-page-3 section 8.1, "Using named pages: page", defines its behavior in terms of whether a box creates a class A break points.

Specifically, I'm looking at this quote:

Applies to: boxes that create class A break points

Taken literally, this excludes block-level boxes that have no siblings. Strictly speaking, such boxes do not create any Class A breakpoints, by definition (since Class A breakpoints are created between siblings; if there no siblings, there are no Class A breakpoints that were created).

Is this exclusion intentional?

This is important, because it impacts whether these elements propagate their page value to their parent box; and that impacts whether or not page breaks might get inserted between the parent box and its siblings (if the parent has class A breakpoints). This is due to the wording here:

The page property works as follows: [...] A child propagates its own start or end page value if and only if the page property applies to it.

Taken literally, this implies that an "only-child" block-level element would never propagate its used page value to its parent, because the page property "does not apply" to the "only-child" element, because it does not create any class A break points.

@fantasai does this make sense and do you recall whether it's intentional that we're excluding propagation from only-child elements here?

dholbert commented 2 years ago

Concrete example: should there be a page break here or not?

<div style="page: a">
  <div style="page: b">Nested</div>
</div>

<div style="page: b">Last</div>

However, Chromium's implementation disagrees with my expectation, and they put all of the content on a single page.

dholbert commented 2 years ago

I suspect the "boxes that create class A break points" qualifier is accidentally too specific -- maybe it needs to include something like: "(or could create class A breakpoints, in the presence of sibling boxes of the same type)"?

i.e. maybe the "Applies to" text here should really say: Applies to: boxes that create class A break points (including "only-child" boxes that would create Class A break points, if they had sibling boxes of the same type)

faceless2 commented 2 years ago

For what it's worth, we put this on a single page and so do every one of the print engines at https://printcss.live.

This type of construct is really common, I've seen plenty of examples that look like <section><div style="page:x">. The question boils down to "is Nested on page A or B": if it's B, there's no break and Chromium is correct. I've no opinion on the exact wording though.

mstensho commented 7 months ago

Indeed, Chromium doesn't do exactly what the spec says at all. Your reading of the spec seems correct, @dholbert . That seems to be exactly what the spec is saying.

I was the one who implemented this in Chromium, and my interpretation back then was to apply it in the same cases as when break-before or break-after apply. That's clearly not what the spec says, though. Now quite sure how I managed to end up with that conclusion. Too much thinking, too little reading? :) There's this mental model of possible class A (and class C as well, actually) break opportunities, and how break-before and break-after values propagate up to them. And one might ask: why should page be any different?

Wouldn't it make sense to change the spec to this effect? There seems to be interop to some extent, at least. Firefox also renders the test in https://github.com/w3c/csswg-drafts/issues/7235#issuecomment-1110350511 onto one page.

Note that making such a change would imply that we can get breaks at class C breakpoints triggered by page.

<!DOCTYPE html>
<style>
  body { margin: 0; }
</style>
<div style="border:solid;">
  <div style="float:left; width:100px; height:100px; background:hotpink;"></div>
  <div style="clear:both; page:different;">
    next page.
  </div>
</div>