w3c / csswg-drafts

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

[css-overflow-4] Ellipsizing of text in middle of string #3937

Open hibachrach opened 5 years ago

hibachrach commented 5 years ago

Hello,

There are many cases in which the information at the beginning & end (but not middle) of a string of characters are important, especially in technical identifiers (e.g. URLs, file names, library call numbers, etc.). It would be wonderful if this was supported in CSS itself. Attempts to do with the current tools available are unattractive and complex at best.

Apologies if this is better addressed in the mailing list--the guidelines and other material online were unclear which is preferred in cases such as these.

I am following on from a previous inquiry led by Sebastian Zartner, to whom I owe thanks. His www-style@w3.org thread from 2013 ended without any conclusions or next steps. Note that I am not the author of the detailed proposal listed below, but merely a web developer interested in highlighting this proposal.

SebastianZ commented 5 years ago

Thank you for picking up my proposal, Harrison!

For reference, my proposal actually included two ideas. The first one was to allow cropping in the middle of the element's content and the second, related one to preserve some part of the contents on smaller element widths.

To avoid discussing two features at the same time, let's focus solely on middle-cropping here.

My proposal back then was to reuse text-overflow for this purpose and simply add a third value to it specifying the cropping in the center of the contents. @MatsPalmgren had another proposal in the related enhancement request for Gecko, which let you move the end ellipsis. Both proposals turned text-overflow into a shorthand and introduced different longhands allowing to control the different partial values separately.

Issues with the proposals, which need to be solved:

  1. Normally, you will only want to crop either at the beginning and/or end or in the middle, but not both.
  2. For middle-cropping you will only want to have ellipsizing but not clipping, so clip should not be allowed for it.
  3. Handling of inline contents other than text.

Sebastian

SebastianZ commented 5 years ago

Additional note: The proposal only covers inline content cropping. There might be cases, in which you'd want to do block-level middle-cropping. Though I guess that's rather related to line-clamp.

Sebastian

frivoal commented 5 years ago

There might be cases, in which you'd want to do block-level middle-cropping.

Would there? on single line ellipsis, doing it it the middle makes sense to me, but on multiline, it seems a lot less useful. Maybe I'm just short on imagination. Do you have examples of when you'd want that?

ghost commented 5 years ago

I would appreciate this feature as well. macOS Finder uses an inner ellipsis likely because the most variation and differentiation in a filename is at the beginning and end of the filename.

jonjohnjohnson commented 5 years ago
<div class="mete">
  <span class="mete-start">When rendering this long sentence&nbsp;</span>
  <span class="mete-end">you will often see a middle ellipsis!!!</span>
</div>
.mete {
  display: flex;
  align-items: baseline;
  justify-content: center;
  height: 1.5em;
  line-height: 1.5em;
}
.mete-start, .mete-end {
  overflow: hidden;
  height: inherit;
  flex: 0 1 auto;
}
.mete-start {
  word-break: break-all;
}
.mete-end {
  white-space: nowrap;
  direction: rtl;
  text-overflow: ellipsis;
  text-overflow: ' ...';
}
.mete-end::after {
  content: '\200E';
}

Here's the utility I use to solve this gap in the spec. But it does have the caveats of not working in webkit, misusing direction, and being tricky to semantically style (em/strong) text across the center boundary, but it is selectable and mostly accessible. :/

https://jsfiddle.net/t5jvns7q/

SebastianZ commented 5 years ago

There might be cases, in which you'd want to do block-level middle-cropping.

Would there? on single line ellipsis, doing it it the middle makes sense to me, but on multiline, it seems a lot less useful. Maybe I'm just short on imagination. Do you have examples of when you'd want that?

Well, the cases are not as strong as the single-line cases, I guess. Though the principle stays the same, i.e. cases, in which you care more about the ending than the middle of the contents.

One use case could be the Inspector panel within browser DevTools, which shows the text contents of the elements. When they span over many lines, it gets quickly hard to skim over the HTML structure. Those could limit the contents to a specific number of lines but crop them in the middle of the contents, so it's easy to skim over them.

Example: Long texts in Inspector

Could be shrinked to someting like in this mockup:

Cropped long texts in Inspector

Sebastian

SebastianZ commented 1 year ago

Giving the issues stated earlier some more thought, I came up with another approach than outlined in my first suggestion.

  • Normally, you will only want to crop either at the beginning and/or end or in the middle, but not both.

We might introduce a text-overflow-position longhand to cover that.

  • For middle-cropping you will only want to have ellipsizing but not clipping, so clip should not be allowed for it.

Some possible options to handle this:

  1. Introduce an auto value and make it the initial value. For start and end positioning of the overflow handling, the used value would then be clip, for middle positioning it would be ellipsis. (That requires checking web compatibility.)
  2. Let clip also apply to middle positioning. (Though clipping the inline content in the middle probably doesn't have any use cases.)
  3. Interpret clip for middle positioning as ellipsis. (Might be unexpected.)
  4. Interpret clip for middle positioning as if end positioning was applied. I.e. clip the contents at the edge where they overflow the element.
  • Handling of inline contents other than text.

This would work very similar to the current definition. I.e. characters and atomic inline-level elements would be removed until the ellipsis fits.

With an auto value as suggested above, the syntaxes might then look like this:

text-overflow = <'text-overflow-handling'> || <'text-overflow-position'> text-overflow-handling = auto | [ clip | ellipsis | <string> | fade | <fade()> ]{1,2} text-overflow-position = [ start || end ] | middle

With names to be bikeshedded, as always. And only the first handling value would be applied if middle positioning is chosen.

The simplest middle-cropping could then be achieved via text-overflow: middle. Some advanced examples would be text-overflow: middle fade(3ch) and text-overflow: start end ellipsis. Doing so, we'd have to define what to do in cases like text-overflow: end start ellipsis fade.

Sebastian

SebastianZ commented 1 year ago

The initial suggestions celebrated 10 years anniversery yesterday. 😄 Maybe we can discuss the latest suggestion while we're at the F2F.

Sebastian

fantasai commented 1 year ago

Random comment: for strings consisting of certain types of formatted text (e.g. URLs) it might make sense for the UA to choose an ellipsis position that's a bit more intelligent than positional from a layout perspective.

jfkthame commented 1 year ago

One question to be considered -- I'm sure it has been discussed previously, but don't have links on hand -- is how middle-cropping behaves in the case of mixed-direction (bidi) content. Does the line first get laid out without cropping, and then content is elided from the visual middle such that the edges are unchanged, or does content get elided from the logical middle of the line and the reduced content then laid out?

So, using uppercase letters to represent RTL characters, if we have a line where the full content is

abcdefghijklmZYXWVUTSRQPON

we have two possible results:

(1) "visual middle" ellipsis would give something like

abcdef…SRQPON

(2) "logical middle" ellipsis, on the other hand, would give us

abcdef…ZYXWVU

I tend to think (2) is the better result in most situations, given that the point of middle-ellipsis is to keep the beginning and end of the content visible, but this might not always be the desired result?

Implementation-wise, there may be some tricky cases here.

SebastianZ commented 1 year ago

Bidi behavior wasn't brought up so far, as far as I can tell. So, thanks for that!

My gut feeling is also to go with option 2, though I have to admit I don't really have much experience regarding bidi text. Also, the case you've shown is the most simple one. What if you have a right-to-left part in an otherwise left-to-right sentence and the cropping happens to show a part of both?

I.e.

abcdefghijklmZYXWVUTSRopq

I'd say the result should be

abcdef…ZYXopq

Though I'm not sure about that.

Sebastian

frivoal commented 1 year ago

Let's use actual words instead of lined-up letters. If we go from this example, and need to delete 5 characters:

he greeted them: ?UOY ERA WOH ,HI

Visual middle gives:

he greeted the…OY ERA WOH ,HI

Logical middle gives:

he greeted the…?UOY ERA WOH ,

Logical middle looks unexpected and confusing to me.

Also, with visual middle, there's no complication if the font isn't monospaced, or if there are multiple fonts or font sizes on the line, whether there's kerning, whether there is some white space collapsing, some ruby… It's a paint based operation, and so the middle can just be geometrically halfway between the start and end edges. Or we could shift it around a bit if we wanted to without any particular complication. In the case of logical middle, it gets a lot messier. Counting code points is easy, but isn't a particularly good proxy for what feels like the middle to a reader, and doing other things seems an unpleasant mix of complicated and arbitrary.

Thinking in terms of use cases, this particular feature request seems to be driven by ellipsis in the middle of file names, URLs, serial numbers, and the like.

C:\Photos\صورة.jpg

Here, the bits that are most important to preserve as C:\ and .jpg. For the rest, I'd argue it doesn't really matter all that much what gets chopped off, and to the extend that it does matter, that we're unlikely to find consistent rules that are ideal in all scenarios. For example, here, whether you're better off chopping some of the file name, or some of the directory name, or a bit of both, most likely doesn't depend on how short or long the file name and directory names are, and more likely depends on what the user is trying to do learn from that path.

All in all, unlike block-ellipsis, where processing things in logical order does seem important to me, for text-overflow: middle ellipsis, I'd argue for visual middle.

jfkthame commented 1 year ago

I suspect that for mixed-direction content, any approach will sometimes give somewhat odd results, but I'm still inclined to think that "logical middle-cropping" is better than visual, if it can be implemented reasonably.

In particular, the case of URLs, file paths, etc., where components of the path are right-to-left seems to me to call for logical cropping. In your extreme example with

C:\Photos\صورة.jpg

it perhaps wouldn't matter much; but in a longer example with multiple RTL directory names, visual middle-cropping is liable to lose the actual filename (leaving the top-level directory), whereas it would probably be more useful to keep the filename and lose the top-level dir (as happens with a purely LTR path).

See https://codepen.io/jfkthame/pen/ExGqBYd for an illustration, where IMO the logical version is preferable -- although any result for mixed-direction paths can be confusing, I think.

As for how to implement logical middle-ellipsis.... I'm not sure, exactly, but I think it's at least worth giving it some more thought. Things like counting codepoints are surely not the answer; it has to be based on measurement of (shaped) text.

SebastianZ commented 1 year ago

Bidi content is definitely hard to handle and may not always provide the best results. Though UAs should try to do their best to output the contents as expected.

Thinking in terms of use cases, this particular feature request seems to be driven by ellipsis in the middle of file names, URLs, serial numbers, and the like.

Yes, file paths and URLs were my main use cases. Therefore, I welcome @fantasai's comment about letting UAs be smart about where to crop the contents.

As for how to implement logical middle-ellipsis.... I'm not sure, exactly, but I think it's at least worth giving it some more thought. Things like counting codepoints are surely not the answer; it has to be based on measurement of (shaped) text.

Yes, measurement-based positioning seems reasonable as we need to keep non-textual contents in mind. And as @frivoal pointed out earlier, textual contents may also differ in different aspects.

Though I think the spec. is already prepared for that by saying

For the ellipsis and string values, implementations must hide characters and atomic inline-level elements at the applicable edge(s) of the line as necessary to fit the ellipsis/string, and place the ellipsis/string immediately adjacent to the applicable edge(s) of the remaining inline content. The first character or atomic inline-level element on a line must be clipped rather than ellipsed.

So, inline contents are layed out and then characters and atomic inline-level elements are stripped off until the ellipsis/string fits. We just need to define that in more detail and specify what "applicable edges" are. Implementation-wise, this probably requires to define an algorithm. Trying to roughly outline one, I'd say:

  1. Check whether the contents fit into the the element without any overflow. If they do, output the contents.
  2. Strip one character or atomic inline-level element from one of the applicable edges. If there are multiple edges, strip alternating from the first and the second one. For middle-cropping, UAs may define some weighting for when to alternate between the edges.
  3. Check whether the contents including the ellipses/strings fit. If they do, output them. If not, repeat from step 2.

Sebastian

hibachrach commented 1 year ago

But it has the caveats that it doesn't work in webkit

@jonjohnjohnson fwiw, this seems to work for me in Safari Version 17.0 (19616.1.27.211.1)

image
css-meeting-bot commented 7 months ago

The CSS Working Group just discussed [css-overflow-4] Ellipsizing of text in middle of string, and agreed to the following:

The full IRC log of that discussion <fantasai> astearns: are we going to do this, or punt it?
<fantasai> SebastianZ: Longstanding thing I proposed 10 years ago, a way to crop content of an element in the middle instead of at the beginning or end
<fantasai> ... proposal went through some iterations
<fantasai> ... current idea is to make text-overflow a shorthand and introduce text-overflow-handling and text-overflow-position
<SebastianZ> https://github.com/w3c/csswg-drafts/issues/3937#issuecomment-1624382903
<fantasai> text-overflow = <'text-overflow-handling'> || <'text-overflow-position'>
<fantasai> text-overflow-handling = auto | [ clip | ellipsis | <string> | fade | <fade()> ]{1,2}
<fantasai> text-overflow-position = [ start || end ] | middle
<fantasai> SebastianZ: we cover the current behaviors, plus cropping
<fantasai> SebastianZ: also outlined rudimentary algorithm later on
<florian_irc> q+
<kizu> q+
<fantasai> SebastianZ: anyone on the call have comments?
<astearns> ack florian_irc
<fantasai> florian_irc: my main concern here is the handling of bidi
<fantasai> florian_irc: in general, just like in start/end of line, should do visual cropping not logical
<fantasai> ... logical cropping is going to be having some strange cropping
<fantasai> s/cropping/questions/
<fantasai> ... in generalized case, including bidi, makes me worry
<fantasai> ... because when you chop start/end, clear what happens, but if you crop middle you have to move the other parts
<fantasai> ... suspect it's more complex than we wish
<astearns> ack kizu
<fantasai> kizu: I don't have any opinion on bidi, but ellipsing in the middle is something I've wanted for more than 10 years
<jfkthame> q+
<fantasai> kizu: Last time, there was concern about not allowing clipping in the middle
<fantasai> kizu: but still good way to do it, if it's exactly in the middle then author can position something interesting there
<fantasai> kizu: but this will require browser to know
<fantasai> kizu: other than that, lots of people want this
<fantasai> kizu: idk if in this issue or other, if we need an ellipsis in multiline
<fantasai> kizu: in our product we need this, but should discuss separately
<fantasai> kizu: but for single-line, a lot of use cases
<astearns> ack jfkthame
<fantasai> jfkthame: I still disagree with Florian that visual ellipsizing in the middle is the right approach for bidi
<fantasai> jfkthame: in most cases, the most important content will be the beginning of the text and/or the end of the text logically speaking
<fantasai> jfkthame: so those pieces should be preserved
<fantasai> jfkthame: I wonder if, given the complexity/uncertainty, is define middle as a feature but leave the behavior of bidi cases for browsers to experiment with initially
<dbaron> Scribe+
<fantasai> jfkthame: until we see what works in real-world use case
<astearns> ack fantasai
<SebastianZ> +1 to what Jonathan said.
<dbaron> fantasai: I ithnk this makes sense -- the question is whether there's implementor interest. If so, we should spec it.
<dbaron> s/ithnk/think/
<dbaron> astearns: do you want to gate specifying on implementor interest? Or should we start it, mark it at risk, and work on spec in parallel?
<fantasai> astearns: should we gate spec on implementer interest?
<fantasai> florian_irc: in this case, I think yes
<fantasai> florian_irc: we agree that this is hard, and we don't know enough to spec it
<fantasai> florian_irc: so even if we did spec it, we wouldn't be able to get interop-level detail
<fantasai> astearns: even if there's open questions, the majority of use cases aren't bidi
<andreubotella> q+
<fantasai> astearns: it's something devs need and have a use for
<florian_irc> q+
<astearns> ack andreubotella
<fantasai> andreubotella: Chromium has an implementation of ellipsis in the middle that they use for file selection
<fantasai> andreubotella: I don't know what it does wrt bidi, but they have an implementation
<astearns> ack florian_irc
<fantasai> florian_irc: even if not bidi, there's still ambiguity wrt visual or logical middle
<fantasai> florian_irc: if non-monospace font, where is the middle?
<fantasai> florian_irc: effect of disagreeing will be less dramatic, but still will have disagreement
<SebastianZ> q+
<fantasai> florian_irc: but maybe useful enough to spec
<fantasai> florian_irc: would prefer to wait until interest, but not an objection
<astearns> ack SebastianZ
<fantasai> SebastianZ: There was at some point an implementation in XUL
<fantasai> SebastianZ: but they removed it at some point
<fantasai> dholbert: we replaced it with another hack based on HTML+CSS
<astearns> ack SebastianZ
<fantasai> dholbert: we have something, but idk how good it is. Similar to Chromium
<fantasai> astearns: given that there does appear to be something implemented, is that enough?
<fantasai> fantasai: can't speak for Apple, but doubt we'd object
<fantasai> jfkthame: unsure when we'd get to it, but some interest
<fantasai> jfkthame: we know that what we've got doesn't handle i18n well
<fantasai> jfkthame: and partly lack of a spec has discouraged us from being more thorough about integrating with CSS
<fantasai> astearns: I'm inclined to resolve that we start the spec of this, knowing it will be complicated, and it may take awhile
<fantasai> florian_irc: Do we start with SebastianZ's proposal of two longhands?
<fantasai> astearns: seems like a good place to start
<fantasai> fantasai: probably need to bikeshed -handling at some point
<fantasai> astearns: proposed to start?
<fantasai> RESOLVED: Start work on middle ellipsis in css-overflow-4
dbaron commented 7 months ago

For what it's worth, one thing I was going to add to the discussion regarding bidi is that my intuition about real bidi usecases (which are different from the testcases we write!) is that real bidi use cases generally have a dominant text direction and small pieces of text in other directions.

I think that might make me lean towards the idea that visual is fine for the middle like it is for the ends, but I'm also not really an expert on the use cases...

yisibl commented 5 months ago

There might be cases, in which you'd want to do block-level middle-cropping.

Yes, the vue-clamp component implements the ellipsis position, which takes values 'start' | 'middle' | 'end', this on github currently has close to 700 stars. cc @Justineo

https://vue-clamp.vercel.app/#demo

image

nico3333fr commented 1 month ago

Another case we have in Proton Drive: we want to keep the last characters to display the extension of a file (with long filename, for security reasons)

image

We did implement a solution by splitting the filename thanks to this component https://github.com/ProtonMail/WebClients/blob/main/packages/components/components/ellipsis/MiddleEllipsis.tsx but when we have a mix of RTL/LTR, it's a nightmare.

A native solution with an offset would be really helpful there :)

EDIT: some explanations of the issues => https://www.smashingmagazine.com/2022/12/deploying-css-logical-properties-on-web-apps/#mixing-rtl-and-ltr-content