w3c / csswg-drafts

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

[css-overflow] Is continue: discard working in the fragment tree useful? #7708

Open emilio opened 2 years ago

emilio commented 2 years ago

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 like visibility: hidden (i.e., stop painting them) rather than display: 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

tabatkins commented 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.)

emilio commented 2 years ago

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

tabatkins commented 2 years ago

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.

emilio commented 2 years ago

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.

tabatkins commented 2 years ago

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?)

bfgeek commented 2 years ago

One specific difference is the OOFs would propagate up from the clamped content.

tabatkins commented 2 years ago

Ah, in the "become invisible ink overflow" case? Whereas in the "drop the fragments" case the OOFs after the break would just be gone?

bfgeek commented 2 years ago

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.

bfgeek commented 2 years ago

The other difference/side-effect is the geometry APIs

css-meeting-bot commented 2 years ago

The CSS Working Group just discussed continue:discard in the fragment tree.

The full IRC log of that discussion <TabAtkins> Topic: continue:discard in the fragment tree
<astearns> github: https://github.com/w3c/csswg-drafts/issues/7708
<TabAtkins> emilio: making line-clamp work using continue:discard has some side effects
<andreubotella> q+
<TabAtkins> emilio: Based on fragmetnation implies the boxes you clamp don't exist, so OM APIs return 0 sizes, etc
<florian> q+
<TabAtkins> emilio: And implies that like border-bottom disappears due to box-decoration-break
<heycam> q+
<TabAtkins> emilio: I think it would be both easier and more useful to impl line-clamp by clamping both content-height, as it does now, and the scrolalble overflow, and hiding the clamped lines rather thand iscarding fragments
<TabAtkins> emilio: There's been some discussion - I think in general it's a lot easier to implement but similarly useful
<TabAtkins> emilio: So easier to reach unprefixed line-clamp
<iank_> q+
<TabAtkins> emilio: We could decide to ship line-clamp as a longhand for now and decide what to do about shorthands later
<astearns> ack andreubotella
<TabAtkins> andreubotella: it's not clear how line-clamp would work with editting (?)
<astearns> s/(?)/(!)/
<TabAtkins> andreubotella: Not clear where carat woudl go if you move past the clamped line
<TabAtkins> andreubotella: Would be less of an issue with emilio's model
<astearns> ack florian
<TabAtkins> florian: We'd also need to define how padding/etc will work. using fragmentation gets us that, it defines those
<TabAtkins> florian: One of the goals is to avoid reinventing all that
<TabAtkins> florian: It's true that the discarded part, we have incomplete answers about what to do with abspos in there, what happens to the caret, etc
<TabAtkins> florian: So maybe we do use fragmentation, but rather than discard the post-fragmentation is invisible
<TabAtkins> florian: but saying that it's easier to do it visually is in conflict with the existing knowledge that it's in conflict with visual stuff
<TabAtkins> florian: like bidi content
<TabAtkins> florian: in the fragment model, in document order, hen we have enough content to place the ellipsis; that's different from hiding characters at the end of the line
<TabAtkins> florian: another complaint about visual aspect is you hvae no control over what gets elided and whether it happens at sensible line-break points
<TabAtkins> florian: If using fragmentation, the line breaking properties work
<TabAtkins> florian: Another thing which is useful under the current model (and maybe usable under your new model), a lot of people want to clamp at 3 lines, but a lot want to clamp at 100px
<TabAtkins> iank_: still possible
<TabAtkins> florian: Not impossibl, but undefined. Defined with fragmentation, but not defined without.
<TabAtkins> florian: Don't want to display a half-line, for example
<TabAtkins> florian: So I think we can find ways to define things in terms of fragmentation that are less mysterious
<TabAtkins> florian: And also make some statements about "allowable approximations".
<TabAtkins> florian: But I think entirely discard fragmentation would be unfortunate
<TabAtkins> iank_: clarification, the visual model is purely about subsequent lines
<TabAtkins> iank_: Still do layout placement of ellipsis, etc
<TabAtkins> iank_: So not necessarily in conflict with what you want to achieve
<astearns> q?
<TabAtkins> iank_: I don't wanna have a spec where all the impls do emilio's model, and there's a bunch of soft wording about how it's allowed
<emilio> q+
<TabAtkins> florian: yeah point is not to write fiction, it's just that if we do emilio's model because it's more useful, we shouldn't omit the useful properties of the current spec
<TabAtkins> florian: If we treat it as something like a multicol where additional cols aren't painted, you can have an answer to all the API questions
<TabAtkins> iank_: there's still subtle diffs
<TabAtkins> iank_: in emilio's model it's actually desirable that you don't fragment the borders
<TabAtkins> emilio: say you calmp in a nested block with border/padding.
<TabAtkins> emilio: it has five lines, you clamp at 3, per fragmentation you're supposed to hide the border padding at the bottom
<TabAtkins> fantasai: which element has line-clamp here?
<TabAtkins> emilio: the bfc
<TabAtkins> fantasai: so inside the bfc you have a text with 5 text lines
<TabAtkins> fantasai: the bfc says line-clamp:3
<TabAtkins> fantasai: so you clamp after three lines, then what's after is clamped
<TabAtkins> emilio: no
<TabAtkins> iank_: You're just clamping the content box. You set the content box to the size afte clamping and then layout as normal.
<iank_> https://www.software.hixie.ch/utilities/js/live-dom-viewer/?saved=10735
<TabAtkins> [retreading the previous example]
<TabAtkins> emilio: the auto height of the inner box is 3 lines tall (plus mbp)
<TabAtkins> florian: So you're reinventing fragmentation...
<TabAtkins> emilio: no fragment would crop the border
<TabAtkins> florian: yeah we have box-decoration-break that lets you control it
<TabAtkins> iank_: well they're not repeated, because this *isn't* fragmentation
<TabAtkins> [missed]
<TabAtkins> florian: If we do it with fragmentation you can choose whether to clip those borders or not
<TabAtkins> iank_: You can here, with border:0
<TabAtkins> florian: No you can't, you can't predict whther the clamp activates or not
<TabAtkins> florian: fragmentation already solved this, dunno why we're reinventing
<TabAtkins> iank_: I think this is a small edge case and most people would expect the behavior from emilio's model
<TabAtkins> astearns: agree this is probably small, but there are tons of decisions in this space about what to do after a fragment break, and we'd have to reinvent all of these
<TabAtkins> emilio: don't think it's reinventing, we just do what we do if you clamp the auto size and visually hide the overlap
<TabAtkins> iank_: very similar to empty-cells on tables, or similar to visibility:hidden but not quite
<TabAtkins> astearns: ther'es a long queue
<florian> q+
<florian> ?
<TabAtkins> heycam: it's probably more like visibility:collapse on those additional lines at the end, they take up no space and aren't rendered
<TabAtkins> iank_: a little diff bc collapse applies to a container, and it of ten gets smushed in size and ther'es some other effects, but yeah
<astearns> ack heycam
<TabAtkins> iank_: the way we'd implement is exactly like empty-cells
<TabAtkins> heycam: at a high level in wk, i think we support getting to the full fragmentation model
<TabAtkins> heycam: But we'll need an interim solution, maybe emilio's or similar
<TabAtkins> heycam: think it would be useful to enumerate the diff between this and the full fragment solution so we can see what it's most similar to
<TabAtkins> heycam: and how likely it is we run into compat issue in the future
<TabAtkins> heycam: like gBCR() effects, etc
<TabAtkins> heycam: If that would change between the two solutions, that might be risky
<astearns> ack iank_
<TabAtkins> iank_: broadly i'm supportive of emilio's suggestion
<TabAtkins> iank_: webdevs strongly desire an unprefixed line-clamp
<TabAtkins> iank_: We, Blink, are probably the closest to ahving a fragmentation solution, but still a ways away
<TabAtkins> iank_: emilio's suggestion means all engines can ship something highly interoperable fairly quickly that will satisfy webdev demands
<TabAtkins> iank_: dont' want fiction, so if we do emilio's, want it in the spec
<TabAtkins> iank_: emilio's gets us there very quickly
<TabAtkins> iank_: I don't think emilio's and fragmentation are exclusive
<TabAtkins> astearns: If we come up with a list of things that are going to be different, how can we move from one to the other?
<TabAtkins> iank_: I don't think that we will
<TabAtkins> iank_: I think we'll be shipping whichever we start with
<TabAtkins> iank_: So like, I don't believe3 we'll be able to straight unprefix -webkit-line-clamp even with emilio's solution, bc devs are already depending on scrollable overlow returning a particular value to tell if clamping applied
<TabAtkins> iank_: I suspect we'll get somethign similar
<TabAtkins> iank_: with abspos at the end, for example
<TabAtkins> heycam: so what i'm hearing is that if we come to the full solution it will need a switch
<TabAtkins> iank_: I think that's ok; they're related problems but not necessarily the same
<TabAtkins> iank_: When we want to truncate content and continue it in a different fragmentatin, i wouldn't be sad if that was a different set of fragmentation properties
<TabAtkins> iank_: people are today using prefixed line-clamp and unhappy about it, we can all ship an unprefixed line-clamp with emilio's solution
<TabAtkins> astearns: but it's still different than emilio's?
<TabAtkins> iank_: P sure we can translate most of it over, only big compat change will be the scrollable overflow size change
<astearns> ack emilio
<astearns> ack florian
<TabAtkins> florian: I don't want fiction either, so I'm happy to make accommodations so we can match impls
<TabAtkins> florian: but i wanted to circle back to one potential differenence, because i didn't understand an earlier answer
<TabAtkins> florian: with emilio's, is it possible to "clamp after however many lines it takes to reach 300px"?
<TabAtkins> emilio: could be feasible, define that instead of "hide lines after the third" you'd hide all lines whose block-end edge is after 300px
<TabAtkins> florian: so you'd size the container to 300px, fill it in, start filling in content, then remove after...
<TabAtkins> emilio: not remove
<TabAtkins> florian: you said you'd draw the mbp of children at the bottom, so you'll need to make room to insert those back
<TabAtkins> florian: Note it's not the containr border i'm talking about, it's the content element's border
<TabAtkins> florian: before ocunting lines you don't know how many lines you'll take
<TabAtkins> fremy: you add both top and bottom mbp as you add it, then fill in lines until you hit the limit
<TabAtkins> iank_: yup
<TabAtkins> iank_: our -webkit-line-clamp will already abort and retry for compliated reasons. this is fine
<TabAtkins> florian: what troubles me is not that it's undoable, clearly it is and is even simpler, but it will have something *very similar* to fragmentation which isn't quite fragmentation.
<TabAtkins> astearns: which makes you uneasy
<TabAtkins> florian: yeah
<TabAtkins> florian: The bidi part I'm not sure how you solve
<TabAtkins> florian: we don't control what chunk of text on the last line is okay to remove
<TabAtkins> florian: this is a known problm of the existing paint-based ellipsis
<TabAtkins> emilio: i think blink does layout-time ellipsis
<TabAtkins> emilio: presuambly they ahve to reshpare arbitrary content when inserting it to avoid clipping
<TabAtkins> florian: and it can push content around?
<andreubotella> q+
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<TabAtkins> iank_: I'll ahve to double check, but i think we'll reshape, like if you land on a bad ligature we'll go back and split it
<TabAtkins> florian: it's not just painting a ligature, it's about dropping letters or a whole word
<TabAtkins> florian: simila for an abspos in the content, the static position changes depending on whether it's pushed to the next line or not
<TabAtkins> iank_: I think abspos are break oppos in our impl for this reason
<TabAtkins> astearns: next queue
<astearns> ack fantasai
<TabAtkins> fantasai: there's a number of directions people ahve wanted to extend this in, and starting from fragmentation model gets you to a bunch of different places that we want to end up
<TabAtkins> fantasai: while starting from a visual model doesn't
<TabAtkins> fantasai: I also pasted a funny test case
<TabAtkins> fantasai: it's p weird
<fantasai> https://www.software.hixie.ch/utilities/js/live-dom-viewer/?saved=10738
<fantasai> fantasai: This is the model we *want*?
<TabAtkins> andreubotella: regarding ellipsis, in current fragmentation there's block-ellipsis where youc an repalce the final lines with something
<TabAtkins> andreubotella: how would this work?
<TabAtkins> andreubotella: if the string has rtl and ltr characters?
<TabAtkins> florian: It's specified, i don't recall the details. I think we insert the string as a string without wrapping oppo and with bidi isolation
frivoal commented 2 years ago

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.)

  1. 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?

  2. 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.

  3. 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:

    1. Is the bottom border kept or not?
    2. Is the height of this border taken into account when determining how much content to collapse/discard under the max-height constraint?
    3. Is the answer the same for padding (probably)?
    4. Is the answer the same for margins (maybe)?
  4. 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.

  5. 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>
  6. 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.

  7. If there's a rel-pos anchored in the discarded/collapsed lines, what happens to it?

  8. 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?

  9. If there's a float anchored in the discarded/collapsed lines. What happens to it?

  10. 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?

  11. 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?

  12. 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?

  13. 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?

  14. 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?

  15. 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?

  16. 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?

  17. 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?

  18. How do the intrisinsic size keywords resolve on the height of the truncating/containing box?

  19. How do the intrisinsic size keywords resolve on the truncated box?

  20. How do you insert the ellipsis text on the last line that remains:

    1. Does it remove text in logical or visual order (before/after bidi reordering)?
    2. Where does the ellipsis get placed, if inserted in a complicated bidi phrase?
    3. 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?
    4. 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.
    5. Is the ellipsis text drawn in the block's font/font-size, the removed text's font/font-size, or something else?
    6. 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?
    7. What happens if ellipsis text is too long to fit the line?
  21. What happens when you select all on the page and copy to the clipboard? Do we get the hidden content? What about the ellipsis?

  22. 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.

andreubotella commented 1 year ago

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.

With that, this is how this prototype handles some of these questions. > 3. If the article contains a div (which itself contains all the content) which has m/b/p, what does that do? > ```html >
>
../.
>
> ``` > > In particular: > > 1. Is the bottom border kept or not? > 2. Is the height of this border taken into account when determining how much content to collapse/discard under the `max-height` constraint? > 3. Is the answer the same for padding (probably)? > 4. Is the answer the same for margins (maybe)? The bottom padding and border is kept, but the bottom margin isn't. (This is something that is currently observable in Chromium's implementation of `-webkit-line-clamp`.) In particular, if you have a div with m/b/p whose only content is a div with m/b/p, and the clamping happens in the inner div, the inner div will also not keep its margin. If the m/b/p for both elements are symmetric, you can observe that as a difference in the actual spacing between the top and bottom: ![image](https://github.com/w3c/csswg-drafts/assets/8225977/5a325e3e-8a74-4362-937b-2c3f88e313e7) > 4. If the article contains a div which has m/b/p, and there's some more text nodes after that, what does that do? > ```html >
. > ... >
../.
> ... >
> ``` > > Same question as the (3), but taking into account the presence of text nodes outside of the div. The line count is part of the formatting context, so if you have `max-lines: 3` and there's a line before the div, the div will clamp after 2 lines. If the clamp point is inside the div, it will behave as in (3). If it's before it, the border will not be painted. > 5. 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 ? > ```html >
>
...
>
../.
>
...
>
...
>
> ``` Same as above: the line count adds up across the divs, and any divs after the clamped line will be completely hidden. > 7. If there's a rel-pos anchored in the discarded/collapsed lines, what happens to it? > > 8. 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? My implementation so far hides things that are after the clamp point in the layout tree, regardless of where they show up visually. So (7) is hidden, (8) is shown outside the element. > 9. If there's a float anchored in the discarded/collapsed lines. What happens to it? > > 10. 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? > > 11. 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? Same as above, floats anchored in retained lines are shown, even if they visually overflow or show completely outside of the element's bounds. Floats in the discarded lines are hidden. Whether they're replaced or not doesn't make a difference. > 12. 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? As far as `max-lines` is concerned, it simply grows the line. It's not clear to me how this should work for `max-height`. > 13. 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? Currently I'm always showing abspos. If the block inset properties are not set, the abspos will show up wherever it would without `continue: collapse`, even if it's outside of the article. `bottom: 0` takes it to the bottom of the "collapsed" article box. > 14. 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? Chromium's implementation of `-webkit-line-clamp` ignores all of those, so my prototype does as well.
bfgeek commented 1 year ago
  1. 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.

  1. 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.

  1. 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.

  1. 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.

  1. 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.

  1. How do you insert the ellipsis text on the last line that remains:

These questions don't seem specific to the "collapse" behaviour.

  1. 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).

  1. Is the discarded content in the accessibility tree?

Likely yes.

tabatkins commented 1 year ago

So in summary the rules appear to be:

SebastianZ commented 1 year ago
  • 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 were visibility: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

frivoal commented 1 year ago
  1. How do you insert the ellipsis text on the last line that remains:
    1. Does it remove text in logical or visual order (before/after bidi reordering)?
    2. Where does the ellipsis get placed, if inserted in a complicated bidi phrase?
    3. 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?
    4. 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.
    5. Is the ellipsis text drawn in the block's font/font-size, the removed text's font/font-size, or something else?
    6. 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?
    7. 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.

frivoal commented 1 year ago

Here's where I'm at. We have two different approaches.

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.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-overflow] Is continue: discard working in the fragment tree useful?, and agreed to the following:

The full IRC log of that discussion <fantasai> TabAtkins: We have the 'continue: discard' functionality, part of 'line-clamp' feature
<fantasai> ... can say element only has 3 lines of text, ellipsized, discard the rest
<fantasai> ... used to be defined in a very bizarre way in WebKit
<fantasai> ... want to change
<fantasai> ... Currently defined in terms of fragmentation
<fantasai> ... we already have a good definitionof how fragmentation works
<fantasai> ... Emilio and Ian both have perf concerns about invoking fragmentation
<fantasai> ... and wanted to address this in a simpler manner
<fantasai> ... that accomplishes the right thing
<fantasai> ... but lets us do the rest of the stuff -- suppression, question of what happens to stuff after cut point -- in a cheaper simpler way
<fantasai> TabAtkins: Florian had a list of questions, which didn't have clear answers
<fantasai> TabAtkins: Andreu and Ian went through the list of questions
<fantasai> TabAtkins: and we summarized at the end
<fantasai> TabAtkins: a few open questions, but I think that overall this looks reasonably well-defined
<Rossen_> q+
<Rossen_> q_
<Rossen_> q-
<fantasai> TabAtkins: assuming it is in fact better for perf, seems it also accomplishes the same thing for author purposes
<chrishtr> q+
<florian> q+
<fantasai> TabAtkins: so, question is, Florian do you still have concerns?
<andreubotella> q+
<fantasai> TabAtkins: Should we continue to pursue this approach and spec it out?
<iank_> q+
<Rossen_> ack chrishtr
<fantasai> chrishtr: It's not just perf, it's also very difficult to implement fragmentation definition in the spec
<fantasai> chrishtr: so I think there's a huge practicality advantage to Emilio's proposal
<Rossen_> ack florian
<fantasai> florian: Many of the questions have been answered, and I'm now less fuzzy on how it works, so that's helpful
<fantasai> florian: Some questions which are important haven't been answered yet, so I suspend judgement until I understand how that works
<fantasai> florian: in terms of complexity, yes, version that involves fragmentation is more complex
<fantasai> florian: however I wonder if the difference isn't overstated
<fantasai> florian: given Andreu has been able to prototype both
<fantasai> florian: So it seems more easily within reach than originally suspected
<fantasai> florian: However, I'd like to move away from overall battle about the approach without discussing the details
<fantasai> florian: just having a meta discussion slows us down
<fantasai> florian: we should write both down
<fantasai> florian: to be really sure what we mean
<fantasai> florian: The fundamental mechanics are different, but at the edges there are likely details that can inform each other
<fantasai> florian: E.g. A few interesting questions have been raised about fragmentation, and I think there are answers
<fantasai> florian: and for alternative approach, questions that I'd like answers
<fantasai> florian: so my preference would be to spec both, and use the implementations from Andreu to explore compat, performance, and usefulness to authors
<fantasai> florian: In the trivial cases, both will do the same thing
<fantasai> florian: but if you try to apply to more complex content, there will be differences in behavior
<fantasai> florian: and being able to see those results will help us understand whether one is better, or if each is better in different cases
<fantasai> [missed]
<fantasai> andreubotella: I agree with Florian in that maybe we should try to figure out both approaches at the spec level
<fantasai> andreubotella: and use the prototypes
<Rossen_> ack andreubotella
<fantasai> andreubotella: in terms of implementation complexity, 'continue: discard' in Chromium took me maybe three months (not all in one set)
<chrishtr> q+
<fantasai> andreubotella: with multicol/overflow columns you have discarded behavior... I prototyped that first
<fantasai> andreubotella: I had to be judicious in which assertions to fire when boxes were not laid out, but otherwise not much difficulty
<fantasai> andreubotella: implementing lne-clamping on top of that was not hard
<fantasai> andreubotella: implementation in Firefox, which doesn't have fragments as output would be a lot more complicated
<fantasai> andreubotella: not impossible to do without re-architecting, might have more perf cost.
<fantasai> andreubotella: my understanding is WebKit is working to output fragments, and WebKit did not want to block on them being able to implement the new model
<Rossen_> ack iank_
<fantasai> iank_: Wrt implementability, I think Blink is in the best situation for 'continue: discard'
<fantasai> iank_: but at the end of the day, I'd like this feature in all engines
<fantasai> iank_: implementability will be far easier with 'continue: collapse'; same in WebKit
<florian> q+
<Rossen_> ack chrishtr
<fantasai> chrishtr: to add on about implementation, thanks for details andreubotella
<fantasai> chrishtr: 3 months is what I would have expected
<fantasai> chrishtr: because we have new layout architecture, we can build this on top
<fantasai> chrishtr: I don't think that it's easy at all to do it in WebKit or Gecko, and would have multi-year delay to get feature in hands of developers
<fantasai> chrishtr: and it's a highly requested feature
<fantasai> chrishtr: as I understand it, the clipping version does solve a lot of their problems, and is way way easier in engines that haven't invested into fragment-based architecture
<fantasai> chrishtr: My proposal is to add another value to the spec that is the clipping version
<fantasai> chrishtr: don't remove the other one
<fantasai> chrishtr: could even ship the other version also
<fantasai> chrishtr: but in the nearer term, could implement the second property
<andreubotella> q+
<fantasai> chrishtr: and then be able to compare in practice, what are the gaps, and allow engines to prioritize adding the second version over time
<fantasai> florian: I agree we should spec both. I don't think I'm ready today to decide which should be invoked by the `line-clamp` shorthand
<fantasai> florian: because it would be different values on 'continue', e.g. 'continue: discard' vs 'continue: collapse'
<Rossen_> ack florian
<fantasai> florian: if we can agree on that today, we can make some progress. Going further, I have more issues
<fantasai> chrishtr: so we'll spec 'continue: collapse', write down complete spec, add tests, work through issues, and then come back to group
<fantasai> florian: and while we're doing this, we can make progress on both variants
<fantasai> florian: that sounds good to me
<TabAtkins> fantasai: I'm a little confused about the assertion that Gecko doesn't work on a fragment basis
<TabAtkins> fantasai: the fundamental layout object in gecko is a fragment; the wholel ayout algo is based on that
<Rossen_> ack fantasai
<Zakim> fantasai, you wanted to comment on Gecko
<emilio> q+
<TabAtkins> fantasai: Boxes aren't even a first-class object, fragments are, and boxes are a linked chain
<TabAtkins> fantasai: So I'm not sure I udnerstand why this is more difficult in gecko than another engine
<TabAtkins> fantasai: not that I disagree with the approach, necessarily, just confused
<Rossen_> ack emilio
<fantasai> emilio: The main issue is that fragments cannot easily be discarded. So to implement continue:discard, you need to lie and keep the layout object around, and push it into a list of things that haven't been laid out, and figure out how that interacts with everything else
<fantasai> emilio: it's not only implementability, but what does "discard" mean for a lot of the things that interact with layout tree, like OM, caret movement, etc.?
<Rossen_> ack andreubotella
<fantasai> andreubotella: I'm not sure we should ship both variants in non-experimental builds of engines
<fantasai> andreubotella: if we agree that discard is better, which I'm not sure we agree, but we ship collapse first, then authors will depend on that. I'm not sure that's what we want to encourage
<Rossen_> q?
<chrishtr> if collapse works for a developer use case that's great. if it doesn't and a browser supports discard, they'll use that
<fantasai> Rossen_: so the last agreement was that we a path forward to experiment with both
<fantasai> florian: Proposal would be to spec 'continue: collapse', but an issue in the spec about whether 'line-clamp' invokes that or discard
<fantasai> florian: work through issues in both, and see where that takes us
<florian> s/but an issue/put an issue/
<fantasai> Rossen_: ok, let's take a resolution on that
<fantasai> PROPOSAL: Spec 'continue: collapse', add issue about whether 'line-clamp' invokes 'discard' or 'collapse'
<fantasai> RESOLVED: Spec 'continue: collapse', add issue about whether 'line-clamp' invokes 'discard' or 'collapse'
<florian> s/that or discard/that or 'continue: discard'
andreubotella commented 9 months ago

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.

superuserpro commented 3 months ago

Try https://csser.space/questions/challenges-arising-from-the-offset-in-an-overflowing-div

andreubotella commented 2 months ago

I forgot to mention it over here, but I have a PR for continue: collapse up at #10816. PTAL.