Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-pseudo] Multi-line ::first-letter #2254

Open
Loirooriol opened this issue Feb 1, 2018 · 22 comments
Open

[css-pseudo] Multi-line ::first-letter #2254

Loirooriol opened this issue Feb 1, 2018 · 22 comments

Comments

@Loirooriol
Copy link
Contributor

Loirooriol commented Feb 1, 2018

CSS Pseudo says

The ::first-letter pseudo-element represents the first typographic letter unit on the first formatted line of its originating element [...]
Punctuation (i.e, characters that belong to the Punctuation (P*) Unicode general category) that precedes or follows the first typographic letter unit must also be included in the ::first-letter pseudo-element.

Then, consider this case:

<p>‘T</p>
p {
  width: 0;
  word-wrap: break-word;
}
p::first-letter {
  background: lime;
}

The first line only has , which is punctuation but not a typographic letter unit.

The second line has T, which is a typographic letter unit, but it's not on the first formatted line.

So, according to the spec, I would expect no ::first-letter pseudo-element. But it seems to exist in all major browsers, despite no interoperability: https://jsfiddle.net/gv9snq9g/

screenshot2

@FremyCompany
Copy link
Contributor

lol :)

The trick is that you need to build the first letter before you can build the line, so there is no way the first letter can depend on the first line in its definition. I guess the definition should just be changed.

Just think of a case with width:10px; font-size:1px + ::first-letter font-size:10px (if you don't apply first-letter, you have a first-letter, but if you do, you don't; it just cannot work)

Now whether Firefox and Chrome/Edge are right is another question, but I doubt we will see much practical cases where this happen in the wild. I would assume that in Firefox, the first letter is automatically closed when you go to a new line, while in Edge/Chrome once its boundaries have been decided they are not revisited. I'm not sure if any of those behaviors make sense.

@Loirooriol
Copy link
Contributor Author

Just think of a case with width:10px; font-size:1px + ::first-letter font-size:10px (if you don't apply first-letter, you have a first-letter, but if you do, you don't; it just cannot work)

This also happens with ::first-line, e.g. you can use a big letter-spacing so that the last word does not fit and goes to the next line, where there is no letter-spacing so then it could fit in the available space in the first line. Then browsers leave it in the second line: https://jsfiddle.net/pp4euopt/

So if browsers can know what ends up being in the first line and what in the second line when using ::first-line, I don't see why it should be different for ::first-letter.

@FremyCompany
Copy link
Contributor

Just think of a case with width:10px; font-size:1px + ::first-letter font-size:10px (if you don't apply first-letter, you have a first-letter, but if you do, you don't; it just cannot work)

This also happens with ::first-line, e.g. you can use a big letter-spacing so that the last word does not fit and goes to the next line, where there is no letter-spacing so then it could fit in the available space in the first line. Then browsers leave it in the second line: https://jsfiddle.net/pp4euopt/

That scenario is very different. Whether a word is contained in the first line or not does not threathen the existence of the first line. There is always going to be a first line, and it might very well overflow the line width if there is no other option. I don't think we want the first-letter to be allowed to overflow the first line if it can be broken up.

While you are building the first line, you are adding things to it until you cannot add things to it. While it is possible to do the same for the first letter (like Firefox is doing), it is not possible in that scenario to guarantee that the first-letter always include a letter. In Edge and Chrome, the first-letter always include a letter, but then you cannot guarantee it will fit the first line. You cannot easily have both.

The problem is that you seem to want the first-letter to not exist if all the glyphs of the first letter cannot fit the first line, which is something you can only know once you have built the first line (which is necessarily built after you have built the first letter).

Now, you could always restart the layout ignoring the first letter if you happen to have to break inside the first letter, but restarting the layout for that seems like a waste of time. Also, like I said, restarting the layout without the first letter styles applied would actually result in a first-letter existing so the state would be contradictory.

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Feb 1, 2018

The problem is that you seem to want the first-letter to not exist if all the glyphs of the first letter cannot fit the first line

Well it's not that I want it, it's what the spec says if I understand correctly. But I just noticed neither Firefox nor Edge require a typographic letter unit, just punctuation suffices to create a ::first-letter, https://jsfiddle.net/pp4euopt/1/. So then it makes sense ::first-letter doesn't disappear when the typographic letter unit does not fit in the first line.

So I think that:

  • The spec should standardize what Firefox and Edge do and not require a typographic letter unit.

  • ::first-letter should be restricted to the first line, because it is supposed to inherit from ::first-line.

    On Chrome, this means that ::first-line can affect multiple lines, which is bad.

    On Edge, this means that not all ::first-letter pseudo-elements inherit from ::first-line, which contradicts CSS Pseudo.

So Firefox does it correctly.

@csnardi
Copy link
Contributor

csnardi commented Feb 2, 2018

Also related is #2164, since Chrome/WebKit interprets a new line to be whitespace.

@FremyCompany
Copy link
Contributor

Reading your latest proposal, yes, this does make sense, and I agree with you.

@tabatkins tabatkins added the css-pseudo-4 Current Work label Feb 6, 2018
@fantasai
Copy link
Collaborator

Agenda+ to accept @Loirooriol’s proposal in #2254 (comment)

@css-meeting-bot
Copy link
Member

css-meeting-bot commented Jan 13, 2021

The CSS Working Group just discussed [css-pseudo] Multi-line ::first-letter, and agreed to the following:

  • RESOLVED: ::first-letter pseudo element is closed at the end of the line even if the content that would otherwise be part of it is wrapped to the next line
The full IRC log of that discussion <dael> Topic: [css-pseudo] Multi-line ::first-letter
<dael> github: https://github.com//issues/2254
<dael> oriol: Problem is theoretically first-letter should be in first-line. If block container is narrow enough it can happen that first-letter will span multiple lines.
<dael> oriol: I had a proposal to try to define how this should behave.
<dael> oriol: Some parts to this proposal
<dael> oriol: First would be to standardize what FF, old Edge, and WK do which is that if you don't have a typographic letter unit then the first-letter is allowed to match the punct.
<dael> oriol: If you have both punct and letter you incldue both. If you don't it's allowed to only have punct.
<dael> oriol: Second would be if first-letter could span multi-line we restrict it to first-line so it can inherit.
<dael> oriol: Browser that does both parts of this proposal is FF
<dael> Rossen_: Feedback? Any reason why we shouldn't adopt FF behavior?
<dael> Rossen_: Objections to adopt the FF behavior which allows us to...want to make sure we have right resolution
<dael> fantasai: Summary: first-letter speduo element is closed at the end of the line even if the content that would otherwise be part of it is wrapped to the next line
<tantek> +1 that's a good summary fantasai
<dael> Rossen_: Objections?
<dael> RESOLVED: ::first-letter pseudo element is closed at the end of the line even if the content that would otherwise be part of it is wrapped to the next line

@fantasai
Copy link
Collaborator

Edited in. @frivoal or @Loirooriol could you review and let me know if the edits seem good, or if you think something different would be better? Thanks!

@Loirooriol
Copy link
Contributor Author

@fantasai I think the spec should say that if the first formatted line has no typographic character unit, but has punctuation, then the punctuation is the first-letter text.

It seems that different punctuation is allowed before and after the first letter, so it should be clear what happens when there is no first letter.

@frivoal
Copy link
Collaborator

frivoal commented Dec 31, 2021

I think the spec edit is clearer/better than what @Loirooriol suggests in the comment above. This phrasing makes it possible to get partial first letters when the whole thing won't fit the first line, but it doesn't allow patterns of punctuation that would not normally be part of a first letter to do so just because there's no letter on that line, which is what I'm getting from @Loirooriol 's suggestion.

So +1 from me on the spec text.

@frivoal
Copy link
Collaborator

frivoal commented Dec 31, 2021

Actually, while I like the spec text, I don't think it's in the best spot. I'd move it from the end of 2.2.2 to somewhere in 2.2.1 (probably the last thing before the notes). But this is not a strong preference, as I can see arguments for the other way around.

@Loirooriol
Copy link
Contributor Author

Yes, I mean, the new text is good, it covers this case:

<style>
p { width: 0; word-wrap: break-word; }
p::first-letter { background: lime; }
</style>
<p>‘T</p>

But it's not enough, because it doesn't cover

<style>
p::first-letter { background: lime; }
</style>
<p></p>

We basically resolved to align with Firefox, where the punctuation is lime.

Seems a bit strange if is affected by ::first-letter when followed by a letter in another line (so not affected by ::first-letter), but a alone isn't affected by ::first-letter.

@frivoal
Copy link
Collaborator

frivoal commented Jan 1, 2022

I thought it was good that it did not cover that case, as there's no letter/number/symbol to trigger the existence of ::first-letter. To me, that's different from the first situation, which is error handling due to a lack of room, rather than selection of punctuation for its own sake.

@Loirooriol
Copy link
Contributor Author

Well, the behavior in Firefox (and old Edge) seems more consistent to me, leading punctuation is typically included in ::first-letter so it seems reasonable to include it too when there is no letter.

When this was discussed in the WG, nobody provided feedback against aligning with Firefox. François agreed with me on 3 Feb 2018, but now upvoted your comment. So if multiple people have changed their opinion then you should maybe bring it back for discussion.

@frivoal
Copy link
Collaborator

frivoal commented Jan 2, 2022

When this was discussed in the WG, nobody provided feedback against aligning with Firefox. […] So if multiple people have changed their opinion then you should maybe bring it back for discussion.

My impression when we discussed it was that we were focused on what happens when we wrap the line in the middle of what would otherwise be the first letter. For that, I agree to align with Firefox. For the other case of what to do with a first letter that didn't include a letter/number/symbol regardless of wrapping, I didn't realize we were discussing it was well. The title of the issue, the minuted discussion, and the recorded resolution only cover the first case. But I now see that in the github discussion (particularly #2254 (comment)) you talked about the second case as well, and proposed following Firefox there too. Maybe we should discuss that case separately? It's clearly related, but it's kind of a separate point.

@FremyCompany
Copy link
Contributor

To clarify, just like Florian I think I hadn't really noticed that we were discussing changing the rules of what constitutes a first letter.

I don't think changing the behavior of webkit and chrome makes sense here, because I doubt this has much impact in practice, and at first glance it makes sense that first-letter should include a letter.

Changing the spec would require a dev effort which I think would be best spent on something else.

I'm not against the change, however. Just it sure it's worth it. The precious update felt more critical because the status quo resulted in different and incompatible pseudo-elements models in the browsers, which is not great.

@Loirooriol
Copy link
Contributor Author

My impression when we discussed it was that we were focused on what happens when we wrap the line in the middle of what would otherwise be the first letter

Yes, that's true.

the minuted discussion, and the recorded resolution only cover the first case

Well, the minutes say:

<dael> oriol: First would be to standardize what FF, old Edge, and WK do which is that if you don't have a typographic letter unit then the first-letter is allowed to match the punct.
<dael> Rossen_: Feedback? Any reason why we shouldn't adopt FF behavior?

But it's true that the recorded resolution only covers the main part.

I don't think changing the behavior of webkit and chrome makes sense here

WebKit doesn't need to change this (it only needs to change that text in the 2nd line shouldn't be affected by ::first-leter), because it's already matching punctuation alone. All browser do, except Blink. So it seems simpler if it's Blink the one who changes.

It's a corner case and I'm not against saying that ::first-letter doesn't match punctuation alone if that's what most people prefer. It's just that the opposite is simpler for most implementations, and seems more consistent to me.

@fantasai
Copy link
Collaborator

Agenda+ to discuss @Loirooriol's comment above about allowing initial punctuation to form ::first-letter even without a subsequent letter. See testcase

The relevant spec text is this:

If no qualifying text exists, then there is no first-letter text and no ::first-letter pseudo-element.

Historically we have this from CSS1:

When the paragraph starts with other punctuation (e.g. parenthesis and ellipsis points) or other characters that are normally not considered letters (e.g. digits and mathematical symbols), 'first-letter' pseudo-elements are usually ignored.

CSS2 and Selectors 3 doesn't say anything about what happens if there's no letter.

Fwiw, while I think what CSS1 says makes sense, I am quite sympathetic to Oriol's argument about implementation simplicity. Also we're now allowing digits and symbols as possible first “letters”.

@johannesodland
Copy link

johannesodland commented Jan 18, 2023

Changing the spec would require a dev effort which I think would be best spent on something else.

I would argue that dev effort is well spent in this area (::first-letter). None of the browsers implement ::first-letter according to the spec when it comes to including punctuation and white space. They are not interoperable, and I think most browsers have open bugs on this.

I think it is well worth spending time on this to get it right, and dev effort is well spent on implementing ::first-letter so that international authors and users can start using ::first-letter. This is even more important now that initial-letter is landing in Chrome.

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Jan 24, 2023

Testcase

I think it's kinda strange that the spec allows ::first-letter to only match punctuation in image, but then by changing a character which is not in the ::first-letter, punctuation is no longer allowed: . Seems a confusing action at distance.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Multi-line ::first-letter, and agreed to the following:

  • RESOLVED: Restriuction will be relaxed to allow punctuation-only matching
The full IRC log of that discussion <emeyer> Topic: Multi-line ::first-letter
<emeyer> github: https://github.com//issues/2254
<fantasai> -> https://github.com//issues/2254#issuecomment-1367476156
<emeyer> oriol: We discussed in the past what happens if first-letter container is very narrow
<emeyer> …And then would span multiple lines
<emeyer> …We resolved to clamp to match characters in the first line
<emeyer> …Focus of the previous proposal was not addressing this question
<emeyer> …Better to discuss this and clarify
<emeyer> …So: what to do if the first-letter container only contains punctuation?
<emeyer> …Spec currently selects punctuation if there’s another letter character that appears later in the container
<emeyer> …This seems strange; if the letter character is in another line and you remove it, this suddenly makes the first-letter able to match punctuation characters
<emeyer> s/able/unable/
<emeyer> …first-letter should only be allowed to match punctuation
<emeyer> …I think Gecko’s behavior makes more sense
<emeyer> …Some prefer the specification as it is now
<emeyer> Rossen_: Opinions?
<emeyer> (silence)
<emeyer> Rossen_: Any objections to resolving on the option to use Gecko’s behavior?
<emeyer> iank_: Basically logic UAs use to skip punctuation characters would have that logic removed?
<emeyer> oriol: Yes, since the only one affected would be Blink, it would need to start matching punctuation-only containers
<emeyer> Rossen_: I believe the answer is yes, Blink can stop skipping punctuation-only
<emeyer> RESOLVED: Restriuction will be relaxed to allow punctuation-only matching
<emeyer> s/Restriuction/Restriction/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants