Open emilio opened 2 years ago
If it just stopped painting them, then the content would still be overflowing, but scrolling would just reveal a big empty area, yeah? I'm not sure why that would be preferable.
(-webkit-line-clamp
is incredibly hacky and broken, I wouldn't look to it for guidance in any respect.)
Well, we could spec that line-clamp affects the scrollable overflow, by not accounting for overflow caused by clamped lines, the same way it affects the auto block size, right? I think that'd still be much easier to implement and maybe more intuitive to authors
At that point, what's making it different from discarding the fragments after the break, then? You already have the ability to shift the fragments to the next rendering context, so I'm not clear what the problem you're trying to solve here is.
Well, for once, it doesn't change the interactions with the OM (e.g., getBoundingClientRect()
etc keep behaving as if they were in non-fragmented contexts). FWIW in Gecko there's a difference between "pushing stuff to the next page / column" and "making it disappear into the void". We have no precedent for the later I don't think.
So you're proposing we define that the overflow after the break opportunity doesn't break, but instead becomes invisible ink overflow?
(I'm also curious what the essential difference is between those two cases, btw. I would naively think that "push these to nowhere" is similar in difficulty, if not easier?)
One specific difference is the OOFs would propagate up from the clamped content.
Ah, in the "become invisible ink overflow" case? Whereas in the "drop the fragments" case the OOFs after the break would just be gone?
Ah, in the "become invisible ink overflow" case? Whereas in the "drop the fragments" case the OOFs after the break would just be gone?
Yup that's correct.
The other difference/side-effect is the geometry APIs
The CSS Working Group just discussed continue:discard in the fragment tree
.
We've had good discussions during TPAC breaks about what a simpler mechanism than the one currently specified might be, and I have been trying to understand in detail what the suggested approach means.
As a placeholder, let's call this new approach continue: collapse
, in contrast to continue: discard
.
Prior to trying to spec it out, I'd like to make sure we're all on the same page. Here's a collection of situations which I hope will help us confirm whether we agree about the behavior we're talking about, maybe explore some possible variants, and help us evaluate whether we like the resulting behavior. (We might need a break-out session to go through this.)
(In the examples below, a /
indicates where the cut-off point would fall.)
The base case is something like this: an otherwise unstyled article with a bunch of lines, cut after 3 lines, or after 300px
<article style="continue: collapse; max-lines: 3">.../..</article>
<article style="continue: collapse; max-height: 300px">.../..</article>
I think in this situation, there would be no visible difference between the proposed behavior for continue: collapse
and continue: discard
. Right?
If the article itself has a margin/border/padding, what does that do? Nothing special I expect, as it's the content of the article that's getting cliped/discarded/collapsed, and the article itself is unaffected and nothing happens to its m/b/p.
If the article contains a div (which itself contains all the content) which has m/b/p, what does that do?
<article …>
<div style="border: solid red">../.</div>
</article>
In particular:
max-height
constraint?If the article contains a div which has m/b/p, and there's some more text nodes after that, what does that do?
<article …>.
...
<div style="border: solid red">../.</div>
...
</article>
Same question as the (3), but taking into account the presence of text nodes outside of the div.
If the article has several child elements with m/b/p, and we're dropping content from several of them. Do you keep the (now empty) divs after the clamping point at all? if yes, what happens to their m/b/p ?
<article …>
<div style="border: solid red">...</div>
<div style="border: solid red">../.</div>
<div style="border: solid red">...</div>
<div style="border: solid red">...</div>
</article>
How do the previous 3 questions (and any other that seems relevant) interact with box-decoration-break
? Note: box-decoration-break
is already shipping in a least one Browser (Firefox), so while we can retro-fit an initial auto value if needed, we cannot not skip thinking about it altogether.
If there's a rel-pos anchored in the discarded/collapsed lines, what happens to it?
If there's a rel-pos anchored in the retained lines, shifted far enough down that it would be visually after the cut-off point, what happens to it?
If there's a float anchored in the discarded/collapsed lines. What happens to it?
If there's a replaced float anchored in the a retained line. What happens to it? Does it get truncated? Does it stay entirely? What effect does it have on the height of its containing block?
If there's a non-replaced float anchored in an retained line. What happens to it? Does it get truncated? Does it stay entirely? What effect does it have on the height of its containing block?
If there's an tall inline-level box (image, inline-block, orthogonal inline-level box…) in a retained line, does it simply grow the line and the discarding/collapsing works on that bigger line, or something else?
If there's a abspos anchored in the discarded/collapsed lines. What happens to it? If not disappear, what is its static position? Does bottom:0 take it to the bottom of the box as trucated, or the the (invisible) bottom of the theoretical box?
If you're capping by max-lines
, and there are block-level descendants of the continue:collapse
element with more structure than just a pile of lines (nestbed BFCs, block-level orthogonal flow, a table, a grid, a block level image…), do you simply ignore them when counting lines, or something else?
If you're capping by max-height
, and the cut-off point falls into something that has more structure than just a pile of lines (nestbed BFCs, block-level orthogonal flow, a table, a grid, a block level image…), what do you do?
What do you get if you use any of the JS APIs to query about the geometry of boxes entirely within the discarded/collapsed content?
What do you get if you use any of the JS APIs to query about the geometry of boxes partially within the discarded/collapsed content?
How do the intrisinsic size keywords resolve on the height of the truncating/containing box?
How do the intrisinsic size keywords resolve on the truncated box?
How do you insert the ellipsis text on the last line that remains:
What happens when you select all on the page and copy to the clipboard? Do we get the hidden content? What about the ellipsis?
Is the discarded content in the accessibility tree?
If anyone has questions in the same vein, that would help explore the behavior (including but not limited to exposing differences between continue: collapse
and continue: discard
), feel free to add some more.
I've been toying with a prototype implementation of continue: collapse
in Chromium with max-lines
, built on top of the existing -webkit-line-clamp
code. The existing -webkit-line-clamp
behavior is to set the intrinsic size of the element to the block offset of the last line before clamping (plus bottom p/b of that line's ancestor elements, see below), and my prototype additionally skips painting any line boxes, block-level boxes and floats (but not abspos) which are after the clamp point in the layout tree.
- If you're capping by max-height, and the cut-off point falls into something that has more structure than just a pile of lines (nestbed BFCs, block-level orthogonal flow, a table, a grid, a block level image…), what do you do?
If the content isn't on a line it will cut off the content outside the formatting context - this is similar to monolithic content. As with 14 they aren't considered for lines.
- What do you get if you use any of the JS APIs to query about the geometry of boxes entirely within the discarded/collapsed content?
You get the standard geometry as you'd expect if they weren't hidden. This is similar to how visibility: hidden
works.
- What do you get if you use any of the JS APIs to query about the geometry of boxes partially within the discarded/collapsed content?
Same as above. They will be visible if not hidden, and same the same geometry.
- How do the intrisinsic size keywords resolve on the height of the truncating/containing box?
Unclear what you mean by truncating here, but I'll assume this is the box with line-clamp on it. It'll be the height of it in the clamped state.
- How do the intrisinsic size keywords resolve on the truncated box?
Unclear what tracated box means here, but i'll assume a box that was been hidden. It'll behave the same as if it wasn't truncated.
- How do you insert the ellipsis text on the last line that remains:
These questions don't seem specific to the "collapse" behaviour.
- What happens when you select all on the page and copy to the clipboard? Do we get the hidden content? What about the ellipsis?
Unclear - what the expected behaviour would be - this is similar to existing clamping behaviour (e.g. text-overflow).
- Is the discarded content in the accessibility tree?
Likely yes.
So in summary the rules appear to be:
continue
element. (but it still has geometry, observable from JS, as if it were visibility:hidden
).
- everything in-flow after the cut point, or floated after the cut point, has its paint suppressed, and doesn't contribute its geometry to sizing or overflow of the
continue
element. (but it still has geometry, observable from JS, as if it werevisibility:hidden
).
I believe authors want to be able to know the actual geometry of the element. This is partly covered by #9433, meaning, the APIs should only return the retained lines' geometries. (That might also be controlled via an option.)
Sebastian
- How do you insert the ellipsis text on the last line that remains:
- Does it remove text in logical or visual order (before/after bidi reordering)?
- Where does the ellipsis get placed, if inserted in a complicated bidi phrase?
- To make room for the ellipsis text, do we remove any number of individual grapheme cluster or do we respect the various css-text properties governing what are acceptable line-breaking opportunities?
- Is the content removed from the last line to make room for the ellipsis pushed to the discarded lines? That could for example be observed through the static position of abspos elements anchored in the discarded/collapsed content.
- Is the ellipsis text drawn in the block's font/font-size, the removed text's font/font-size, or something else?
- Does ellipsis text affect the height of the line it's injected in if it happens to be the tallest (or only thing) on that line?
- What happens if ellipsis text is too long to fit the line?
These questions don't seem specific to the "collapse" behaviour.
They are. The spec currently answers these questions while assuming continue: discard
is the underlying mechanism. In particular, the insertion of the ellipsis is a layout affecting operation, in order to properly deal with bidi (among other things). It also gives some control over how the insertion works through the various properties that control text wrapping. As continue: collapse
as described so far is primarily a paint-time effect (except for sizing the container), I don't see an obvious way to make the spec's provisions apply, so specific answers are needed.
Here's where I'm at. We have two different approaches.
continue: discard
) takes a dependency on fragmentation and is thereby largely described, though there remains open questions to look into. The other is a new concept (continue: collapse
), whose basic mechanism is described reasonably simply by @tabatkins in https://github.com/w3c/csswg-drafts/issues/7708#issuecomment-1747840639, though there remains open questions to look into.continue: discard
is overall more complex, but it draws on a mechanism we have anyway; improvements to fragmentation interop or additional fragmentation features developped for the sake of continue: discard
benefit other uses of fragmentation, and vice versa. continue: collapse
is overall simpler, but it's something new and isolated.continue: discard
over continue: collapse
, while probably true, should not be overstated: @andreubotella was able to prototype both in a reasonable amount of time.continue: discard
takes a speed bump, but depending on the content that is being skipped, may gain it back because it doesn't need to lay out the parts that are skipped. continue: collapse
is the other way around: likely cheaper to invoke, but still needing to layout the parts that don't get painted and to pay the cost of doing so.continue: discard
is tied to fragmentation, it can be a stepping stone towards continue: fragments
, which I think would be a very powerful and exciting feature; but that does mean its design is constrained by what makes sense for fragmentation. Because continue: collapse
is not tied to fragmentation, we could make choices in its design that are at odds with the notion that there is a fragmented flow that stops somewhere and needs to be able to resume in a subsequent container, if that were to be useful for our specialized context.My suggestion would be to temporarily set aside the question of which approach is the winner to pursue, as that seems to be holding back refining the nuances of each. I'd rather explore in detail what each approach means, resolve issues about them, use experimental implementations to find out about compat, performance, play with the pros and cons of their differences…Though the underlying mechanism is different, there may be things that each approach can learn from the other, and we should explore those.
The good news is that they both fit withing the same framework of interacting properties, as they would both be keywords on the continue
property. I doubt that we will want to support both, but we could, there's no conflict between the two that would prevent that.
So how about that: we write both of them down, file and attempt to resolve issues against either, iterate for a while with insight learned from experimental implementations, and see where that takes us.
The CSS Working Group just discussed [css-overflow] Is continue: discard working in the fragment tree useful?
, and agreed to the following:
RESOLVED: Spec 'continue: collapse', add issue about whether 'line-clamp' invokes 'discard' or 'collapse'
Hey, I recently sent an intent-to-prototype for the collapse variant of line-clamp
in Chrome (https://groups.google.com/a/chromium.org/g/blink-dev/c/CWP5rb--Gyk). Although there isn't spec text for this yet, we've set up an explainer with our understanding of the behavior of this variant (https://github.com/Igalia/explainers/blob/main/css/line-clamp/README.md).
The plan is to currently implement only the line-clamp
property as a longhand, allowing only the values none | auto | <integer [1,∞]>
, and not implementing the continue
, max-lines
or block-ellipsis
properties. The only difference versus what would be possible with these longhands would be removing or customizing the ellipsis text, which seems like a more niche feature. That said, this is just for the purpose of prototyping and we are not locking ourselves into it.
I forgot to mention it over here, but I have a PR for continue: collapse
up at #10816. PTAL.
The main usefulness of it is clipping overflowing content from e.g.
line-clamp
, but it seems it'd be easier (and more compatible with how-webkit-line-clamp
works now) if this behaved more likevisibility: hidden
(i.e., stop painting them) rather thandisplay: none
on the overflowing items?It'd also be easier to implement, generally, and I'm not sure when it'd be less useful. It might be that I'm missing something obvious?
cc @bfgeek @frivoal @fantasai