Re: [csswg-drafts] [css-overflow] Line-clamp and approaches to ellipsis insertion (#10844)

The CSS Working Group just discussed `[css-overflow] Line-clamp and approaches to ellipsis insertion`, and agreed to the following:

* `RESOLVED: Remove characters *at* break opportunities *in* logical order, for line-break`

<details><summary>The full IRC log of that discussion</summary>
&lt;TabAtkins> florian: As you might remember, line-clamp has been specced for a few years based on fragmentation<br>
&lt;TabAtkins> florian: the longhand that triggers that is called continue:discard<br>
&lt;TabAtkins> florian: andreu has been working on an alternative not based on fragmentation, which we're calling continue:collapse<br>
&lt;TabAtkins> florian: aside from the primary diff between these two, one thing was deliberately designed into continue:discard and not discussed much, and apparently assumed away in continue:collapse, I wanted to talk about it<br>
&lt;TabAtkins> florian: on the line you add the ellipsis, how<br>
&lt;TabAtkins> florian: the pre-existing ellipsis mechanism is from text-overflow:ellipsis<br>
&lt;TabAtkins> florian: I argue that's not appropriate here<br>
&lt;TabAtkins> florian: that's for a single line, which is overflowing the line box. you chop it off at the end of the box, and then some, just enought to add the ellipsis char<br>
&lt;TabAtkins> florian: this is a physical operation, it makes sense in that context<br>
&lt;TabAtkins> florian: but in line-clamp we're not overflowing<br>
&lt;TabAtkins> florian: the logical way to remove content in this context is to act like linebreaking. you basically have a line that's a little too short, so you put a little less content in it<br>
&lt;andreubotella> q+<br>
&lt;TabAtkins> florian: this means you chop off from the *logical* end of the line, not the physical end<br>
&lt;TabAtkins> florian: if you don't do this, you'll chop the logical *middle* of the line, missing *two* parts of the text<br>
&lt;TabAtkins> florian: the following lines, and the logical middle of your line<br>
&lt;TabAtkins> florian: if you're trying to read the text, it makes no sense<br>
&lt;TabAtkins> florian: it's also weird if you split in the middle of words<br>
&lt;TabAtkins> florian: dropping at the same boundaries as line wrapping allows you significantly reduces the amount of misunderstandings you can get from chopping text<br>
&lt;TabAtkins> florian: kind of secondary, but still<br>
&lt;TabAtkins> florian: the issue is a bunch of pictures of text asking how weird it is to chop physically rather than logically<br>
&lt;TabAtkins> florian: so what I want is just to establish whether, regardless of discard or collapse, we should indeed preserve this "just do line breaking and break logically" behavior<br>
&lt;TabAtkins> florian: also, now that we know how much stuff to remove for the ellipsis, where do we put it? physical end or logical end of the line?<br>
&lt;TabAtkins> florian: but that's only relevant if we agree on the first<br>
&lt;TabAtkins> addison: i18n discussed this at length recently<br>
&lt;TabAtkins> addison: we're fairly strongly supportive of logical string truncation<br>
&lt;TabAtkins> addison: it means the kept part of the string makes sense<br>
&lt;TabAtkins> addison: and if you made the box wider, the removed text would be at the end of the line and would make sense to come in<br>
&lt;TabAtkins> addison: So we think logical truncation makes the most sense. and is the easiest here, because you find a break point and then proceed, rather than doing a bunch of ranges<br>
&lt;astearns> ack andreubotella<br>
&lt;TabAtkins> andreubotella: currently it's implemented the same as text-overflow:ellipsis in Chrome, after bidi reordering<br>
&lt;TabAtkins> andreubotella: I don't oppose doing what Florian said, my initial impl was just following existing chrome ellipsis behavior<br>
&lt;TabAtkins> andreubotella: but having heard the bidi reasoning, that sounds fine<br>
&lt;emilio> q+<br>
&lt;astearns> ack dbaron<br>
&lt;TabAtkins> andreubotella: might offer some impl challenges, but don't thi8nk they're insurmountable considering the benefit<br>
&lt;TabAtkins> dbaron: my intuition about the logical truncation is that it's sort of like you're doing layout into a shorter line (shrunk by the ellipsis)<br>
&lt;TabAtkins> dbaron: that's one way to think about it<br>
&lt;TabAtkins> dbaron: one subtlety is how you place the ellipsis, whether it's good to be closer to the text or further after doing this shorter-line layout<br>
&lt;TabAtkins> dbaron: so flush with the remaining text, versus flush with the line-end<br>
&lt;addison> q+<br>
&lt;TabAtkins> dbaron: I think I reasonably strongly agree with the consensus on logical truncation, but don't have a strong opinion on placement of the ellipsis<br>
&lt;TabAtkins> dbaron: it's interesting in both cases from a layout perspective<br>
&lt;TabAtkins> florian: addison had an interesting comment about that<br>
&lt;astearns> ack emilio<br>
&lt;TabAtkins> emilio: so we need to agree on ellipsis insertion not messing with following lines layout<br>
&lt;andreubotella> q+<br>
&lt;TabAtkins> florian: in the continue:collapse that's true, but discard it wouldn't<br>
&lt;TabAtkins> andreubotella: depends on how it's implemented<br>
&lt;TabAtkins> andreubotella: in chromium I don't think there's a way to preserve the breakpoint after a linebreak<br>
&lt;TabAtkins> andreubotella: so the way I was planning to go was to do it all at linebreak time, then the displaced content is pushed to the next line<br>
&lt;TabAtkins> andreubotella: but that's not the same as the impl I think emilio is thinking of<br>
&lt;TabAtkins> emilio: it would be silly because you'd still have to do the layout of everything past the break point<br>
&lt;TabAtkins> andreubotella: my impl wouldn't be doing the extra work<br>
&lt;TabAtkins> emilio: so you'd insert it during the first layout pass?<br>
&lt;TabAtkins> andreubotella: yes, tho with line-clamp:auto you'd still get two layouts<br>
&lt;TabAtkins> emilio: I dont' thi8nk we want line-clamp to cause multipass layout<br>
&lt;TabAtkins> andreubotella: you need it for auto, that's "as many lines as fit". not purely a paint-time info<br>
&lt;TabAtkins> andreubotella: unless it is in gecko?<br>
&lt;TabAtkins> emilio: you clamp the inner block and outer block, it's one pass<br>
&lt;astearns> ack addison<br>
&lt;andreubotella> q-<br>
&lt;TabAtkins> (I don't understand any of this, hopefully it makes sense)<br>
&lt;TabAtkins> addison: we talked about positioning in the WG convo<br>
&lt;TabAtkins> addison: our thinking is that the ellipsis generally wants to behave as part of the text<br>
&lt;TabAtkins> addison: the trick is you probably want to provide the equivalent of a strong marker that matches the next inked character's direction<br>
&lt;Bert> q+ to ask how you know what the language/direction of the ellipsis text is.<br>
&lt;andreubotella> q+<br>
&lt;TabAtkins> addison: you need to know if the run is gonna break or not. ellipsis is a neutral character, you want it to jump to the left or right side of the text, according to where the bidi algo would have put the ellipsis in if was actually in the text<br>
&lt;TabAtkins> florian: give it directionality of the thing it replaces<br>
&lt;TabAtkins> fantasai: no, directionality of paragraph<br>
&lt;TabAtkins> florian: using what it replaces intrigues me<br>
&lt;TabAtkins> addison: you don't want it isolated, you want to let bidi just do the job of deciding left or right side<br>
&lt;TabAtkins> addison: the characters just before it only provide half the context<br>
&lt;TabAtkins> fantasai: you also have to extract it from any embeddings<br>
&lt;TabAtkins> fantasai: two approaches you can take<br>
&lt;TabAtkins> fantasai: one is it acts like the preceding char, and attaches to that.<br>
&lt;TabAtkins> fantasai: dont' think we want that<br>
&lt;TabAtkins> fantasai: other is that it belongs to the paragraph<br>
&lt;TabAtkins> fantasai: we're not ellipsizing a particular phrase, we're ellipsizing the whole paragraph, so having it take the paragraph's qualities makes sense<br>
&lt;TabAtkins> fantasai: it also helps show it's a continuation of the paragraph, not the single phrase<br>
&lt;TabAtkins> addison: that's potentially fair, I did some playing with this<br>
&lt;TabAtkins> addison: it kinda behaves normally<br>
&lt;TabAtkins> addison: I think it's worth going offline and writing it down better, describing why it's a good proxy<br>
&lt;TabAtkins> addison: but it is possible that what you're saying it the right answer<br>
&lt;astearns> ack fantasai<br>
&lt;TabAtkins> fantasai: the fundamental questions are logical or physical clipping (I think logical)<br>
&lt;TabAtkins> fantasai: and whether the ellipsis is attached to the immediately preceding character or an attribute of the paragraph itself, and from that the rest falls out<br>
&lt;TabAtkins> florian: I support opening a followup for this. My starting position matched fantasai, but addison's remarks made me think there were subtleties<br>
&lt;TabAtkins> fantasai: since we're breaking form linebreaking proeprties, not per-character proeprties<br>
&lt;TabAtkins> fantasai: it seems like a more natural break, not as strongly attached to the previous character as you would if you broke in the middle of a word<br>
&lt;astearns> ack Bert<br>
&lt;Zakim> Bert, you wanted to ask how you know what the language/direction of the ellipsis text is.<br>
&lt;TabAtkins> Bert: might be different issue, from what I understand it's not always just an ellipsis character, but can be something else<br>
&lt;TabAtkins> florian: the spec has an answer for that, whether that answer is what we want is another question<br>
&lt;TabAtkins> Bert: okay. if it's an ellipsis you can say it's neutral, but if it's something else...<br>
&lt;TabAtkins> fantasai: I also think that case, if it's like "continues on page 25", if you break in the middle eof hot pink small text, but paragraph is generally normal sized black text, you want the "continues on" to follow the paragraph's styling.<br>
&lt;TabAtkins> fantasai: and directinality<br>
&lt;TabAtkins> fantasai: the ellipsis probably needs to be isolated, but it should take the paragraph's directionality<br>
&lt;astearns> ack andreubotella<br>
&lt;TabAtkins> andreubotella: I don't have an opinion on this discussion, but if we end up going with "matching the next/prev character", anything other than the paragraph base directiond<br>
&lt;TabAtkins> andreubotella: I think in the spec it should be specified in terms of the bidi level of the ellipsis character or replacement string<br>
&lt;TabAtkins> andreubotella: Becuase if you're breaking as part of line-breaking, or even afterwards, you wouldn't be placed back further than the bidi algorithm's progress. you'd at least have the levels of the shown characters.<br>
&lt;TabAtkins> andreubotella: this follows, should be the same as adding a LTR Mark character<br>
&lt;TabAtkins> andreubotella: so I think it should be specced to match impls in that degree<br>
&lt;TabAtkins> emilio: agree<br>
&lt;TabAtkins> emilio: I think we should at least agree to not do the physical truncation the naive way<br>
&lt;TabAtkins> emilio: there are multiple ways to do this that makes sense<br>
&lt;TabAtkins> emilio: imagine you don't have the ability to redo the line layout at that tpoint<br>
&lt;TabAtkins> emilio: we should still truncate at a point that makes sense, might mean truncating more text than what you originally needed.<br>
&lt;TabAtkins> emilio: but that's still way better than putting the ellipsis at the physical end<br>
&lt;TabAtkins> emilio: so I think we should at least agree on that, not naive physical clipping where you just remove characters until it fits<br>
&lt;TabAtkins> florian: I agree, but I'm not sure what you're proposing is "enough"<br>
&lt;TabAtkins> emilio: trying to start from a point nobody disagrees<br>
&lt;TabAtkins> emilio: I also feel strongly we shoudln'ta effect layout of following lines, to require no relayout<br>
&lt;astearns> ack fantasai<br>
&lt;TabAtkins> q+<br>
&lt;TabAtkins> fantasai: one possible resolution is you remove up to a valid linebreaking point, not less than that<br>
&lt;TabAtkins> florian: in logical space? or is that a separate resolution?<br>
&lt;TabAtkins> fantasai: separate. Just saying we remove chunk in linebreaking chunks<br>
&lt;xiaochengh> q+<br>
&lt;TabAtkins> addison: aren't those related? can you compute a linebreaking opportunity physically?<br>
&lt;TabAtkins> fantasai: you can't remove a single letter from English, for example<br>
&lt;fantasai> TabAtkins: Emilio, wondering about implications of what you were saying<br>
&lt;fantasai> TabAtkins: seems you do line layout, figure out lines<br>
&lt;fantasai> TabAtkins: on final line, truncate somehow and put ellipsis in<br>
&lt;fantasai> TabAtkins: and missing words don't flow into the next line<br>
&lt;fantasai> TabAtkins: they are just hiding<br>
&lt;fantasai> emilio: right, don't relayout past breaking point<br>
&lt;florian> q+<br>
&lt;astearns> ack TabAtkins<br>
&lt;TabAtkins> andreubotella: Not sure if we should decide today, it has implications on impl<br>
&lt;TabAtkins> emilio: yeah, just wanted to resolve on basic constraints first, like we don't trigger multipass layout<br>
&lt;TabAtkins> emilio: you'd expect clamping to make the layout cheaper, not more expensive<br>
&lt;TabAtkins> andreubotella: i'm not sure if in blink you can drop lines after layout<br>
&lt;TabAtkins> emilio: I think you can, you just don't paint them<br>
&lt;TabAtkins> florian: regardless, I think we should ellipsize in logical order<br>
&lt;Bert> q+ to ask if 'line-clamp: "\0A …"' works to put the ellipsis on a separate line? And if so, can I right-align that line?<br>
&lt;astearns> ack xiaochengh<br>
&lt;TabAtkins> xiaochengh: I agree we should do logical clamping<br>
&lt;TabAtkins> xiaochengh: but seems complicated, no one size fits all. might have different fonts or colors on ellipsis<br>
&lt;TabAtkins> xiaochengh: so I think we need a pseudo-element to style the ellipsis<br>
&lt;TabAtkins> florian: eventually yes, I don't think it's needed as a level 1 feature<br>
&lt;astearns> ack florian<br>
&lt;TabAtkins> xiaochengh: with a pseudo-element we could postpone some of the issues, like where to put the ellipsis (flush with text, or flush with line end)<br>
&lt;TabAtkins> florian: maybe with pseudo we could override some of the decisions, but we'd still need a default answer<br>
&lt;astearns> ack Bert<br>
&lt;Zakim> Bert, you wanted to ask if 'line-clamp: "\0A …"' works to put the ellipsis on a separate line? And if so, can I right-align that line?<br>
&lt;TabAtkins> xiaochengh: yeah but at least we wouldn't have to bikeshed too much since it wasn't as fatal to tet it wrong<br>
&lt;TabAtkins> astearns: no, defaults are still very important<br>
&lt;TabAtkins> Bert: ah, xiaocheng's suggestion just gave me an answer to what happens with the styling of the ellipsis<br>
&lt;TabAtkins> astearns: can we resolve to have line-clamp remove characters at break opportunities in logical order?<br>
&lt;TabAtkins> florian: Knowing there will be follow-up discussions.<br>
&lt;TabAtkins> astearns: concerns?<br>
&lt;TabAtkins> emilio: we can add a "barring impl craziness"<br>
&lt;TabAtkins> emilio: I think everyone agrees this is the right mode<br>
&lt;TabAtkins> florian: yeah, if it ends up impossible we'll have to revisit<br>
&lt;TabAtkins> astearns: so looks like agreement that it's necessary, and if impl blocks it, we'll still need some *third* thing<br>
&lt;TabAtkins> astearns: objections?<br>
&lt;TabAtkins> RESOLVED: Remove characters *at* break opportunities *in* logical order, for line-break<br>
&lt;TabAtkins> florian: so I think we e need to still figure out alignment of the ellipsis, and then andreu and emilio argue about what happens with the remaining stuff on the line<br>
&lt;TabAtkins> emilio: okay<br>
</details>


-- 
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10844#issuecomment-2372644310 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 25 September 2024 00:50:03 UTC