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-text-decor-4] Rethinking text-underline-offset #3118

Closed
litherum opened this issue Sep 16, 2018 · 14 comments
Closed

[css-text-decor-4] Rethinking text-underline-offset #3118

litherum opened this issue Sep 16, 2018 · 14 comments

Comments

@litherum
Copy link
Contributor

litherum commented Sep 16, 2018

There are a couple problems with the current formulation of text-underline-offset.

  • text-underline-offset is meant to be a delta added to wherever the underline happened to be placed, but the location where the underline is placed varies between different browsers and operating systems. The use case this is supposed to solve is "my underline is just a little too high, let's nudge it down a little bit" but because different browsers choose the locations differently, the current formulation doesn't satisfy this use case
  • What does it mean if both text-underline-offset: from-font and text-underline-position: under are applied to the same element? Such a formulation seems fairly meaningless.

In order to fix these problems, I propose the following changes:

  1. Add another value to text-underline-position named something like standard. Come up with some standard formula for the placement of the underline that all browsers can agree on, and state it in the spec. Importantly, don't make this the initial value - it's just an option that authors can specify if they want consistent underlines. I'm not particular on what specific formula is used, but I'll propose font-size / 16 to get the conversation started. (This formula scales linearly with font size, and default-sized text gets a 1px underline gap, which is compatible with most (all?) browsers today)
  2. Move the from-font value from text-underline-offset to text-underline-position.
  3. Update the grammar of text-underline-position such that you can't specify more than one of [auto, standard, under, from-font].
  4. Now, text-underline-offset really can be just a delta, so there's no need for an auto value. Remove the auto value and have it just take a <length>.
  5. While we're at it, text-underline-offset should be able to take a percentage, which gets multiplied by the font size. This would be a good way to make the underline scale as the font size grows.
@litherum
Copy link
Contributor Author

@fantasai
Copy link
Collaborator

fantasai commented Sep 16, 2018

Hi! I think you're a bit confused. :)

text-underline-offset is meant to be a delta added to wherever the underline happened to be placed, but the location where the underline is placed varies between different browsers and operating systems.

text-underline-offset is defined to set “the offset of underlines from their initial position” where the “initial position” is defined in the table below the propdef. It is not up to the UA, that is what the auto value means. Zero sets the underline at exactly that position.

What does it mean if both text-underline-offset: from-font and text-underline-position: under are applied to the same element? Such a formulation seems fairly meaningless.

Good question. from-font should maybe resolve to zero in this case. Or maybe calculate the distance from the alphabetic baseline to the font's preferred position, and then use that distance as the offset from the zero-offset under position.


Add another value to text-underline-position named something like standard.

I'm not convinced this is necessary if we address your other issues... but open to hearing your arguments. :)

Move the from-font value from text-underline-offset to text-underline-position.

text-underline-position is more fundamental positioning--it can swap which side of the text the underline is on, etc.; from-font is really about just adjusting the offset, so I think it really does belong here.

While we're at it, text-underline-offset should be able to take a percentage, which gets multiplied by the font size.

This is a severe oversight and we should definitely fix it. We should maybe try to be consistent about this across this property, letter-spacing and word-spacing (#2165), and ideally, line-height... Maybe in a separate issue, though?

@fantasai fantasai changed the title Rethinking text-underline-offset Sep 16, 2018
@litherum
Copy link
Contributor Author

text-underline-offset is defined to set “the offset of underlines from their initial position” where the “initial position” is defined in the table below the propdef. It is not up to the UA, that is what the auto value means. Zero sets the underline at exactly that position.

Ah, I see. You're right, I didn't realize that this length refers to an offset from the baseline instead of an offset from the browser's auto placement. So 0 would be a terrible value that no one should ever use.

In that case, I guess my complaint is really about the name. Perhaps text-underline-position would be better, but that's already taken 😕

What does it mean if both text-underline-offset: from-font and text-underline-position: under are applied to the same element? Such a formulation seems fairly meaningless.

Good question. from-font should maybe resolve to zero in this case. Or maybe calculate the distance from the alphabetic baseline to the font's preferred position, and then use that distance as the offset from the zero-offset under position.

Applying the font's distance to under-underlines is never what you want. Picking 0 would be better than that.

On the other hand, if you move the value to text-underline-position, you can mechanically forbid this from happening, which seems better.

Add another value to text-underline-position named something like standard.

I'm not convinced this is necessary if we address your other issues... but open to hearing your arguments. :)

As above, I was just confused about this part. I retract this part of the proposal.

Move the from-font value from text-underline-offset to text-underline-position.

text-underline-position is more fundamental positioning--it can swap which side of the text the underline is on, etc.; from-font is really about just adjusting the offset, so I think it really does belong here.

I don't quite understand the difference between "fundamental positioning" vs "non-fundamental positioning". They both are about positioning.

Perhaps an even better solution would be to join the two properties into one, so you could say something like

  • text-underline-position: under 2px to mean "2px beyond the under-underline".
  • text-underline-position: from-font 12.5% to mean "bump up the displacement from the font file by font-size / 8"
  • text-underline-position: baseline 6.25% is the formula I mentioned above about "standard" placement
  • text-underline-position: left baseline 6.25% is the same thing, but specifies that underlines go on the left in vertical writing mode
  • text-underline-position: under from-font is a syntax error

While we're at it, text-underline-offset should be able to take a percentage, which gets multiplied by the font size.

This is a severe oversight and we should definitely fix it. We should maybe try to be consistent about this across this property, letter-spacing and word-spacing (#2165), and ideally, line-height... Maybe in a separate issue, though?

#3121

@kojiishi
Copy link
Contributor

Actually I have to agree with @litherum's original point because:

  • auto is alphabetic baseline, but each browser puts a pixel or two below the baseline. I suspect this means not the default position, but really an offset from the baseline? This is clear then, but clarification appreciated.
  • text-under edge and text-over edge are not interoperable today, and last I looked CSS2, it's not precisely defined enough to be interoperable.
@fantasai
Copy link
Collaborator

I don't quite understand the difference between "fundamental positioning" vs "non-fundamental positioning". They both are about positioning.

Yeah, but one is setting the origin and the other is setting the offset. It's a bit like the relationship of background-origin and background-position...

I guess the important question is really, do these two things need to cascade together or are there typical cases where you'd set one value independently of the other?

@drott
Copy link
Collaborator

drott commented Oct 19, 2018

I guess the important question is really, do these two things need to cascade together or are there typical cases where you'd set one value independently of the other?

I don't have a strong preference on whether they should be one property or two. But I'd prefer to ultimately spec something that makes it hard to apply invalid combinations, such as as the "under" plus "from-font" combination.

@anjia
Copy link

anjia commented Oct 20, 2018

Hi, I prefer from-font is the value of text-underline-offset, then we can use it as followings.

text-underline-position: left;
text-underline-offset: from-font;

and

text-underline-position: right;
text-underline-offset: from-font;

Because if from-font is the value of text-underline-position, it seems impossible to meet the same effects. I'm not sure whether the following codes or something else can do that, according to the proposal made by @litherum above. So, @litherum, could you please explain further for me? Thank you :)

text-underline-position: right from-font;
text-underline-position: left from-font;

Perhaps an even better solution would be to join the two properties into one, so you could say something like ...

@anjia
Copy link

anjia commented Oct 20, 2018

I guess the important question is really, do these two things need to cascade together or are there typical cases where you'd set one value independently of the other?

I think the two separate properties are better, since other shorthand CSS properties are like this, such as text-decoration border background flex etc.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Text decoration.

The full IRC log of that discussion <gregwhitworth> Topic: Text decoration
<Rossen> github: https://github.com//issues/3118
<gregwhitworth> myles: we have two properties
<gregwhitworth> myles: text-underline-offset and text-underline-position
<gregwhitworth> myles: reads out values for each
<gregwhitworth> myles: question is, both of these properties
<gregwhitworth> myles: the problem is only in horizontal WM
<gregwhitworth> myles: both of these describe the vertical position of the underline
<gregwhitworth> myles: the spec does describe some situations on how they play together
<gregwhitworth> myles: what happens if they collide?
<gregwhitworth> myles: there are two possible ways to solve this problem, is rules and also to join them into one property and avoid the bad issues at the syntax scenario
<gregwhitworth> myles: I prefer the latter as it's intentional and mechnaical
<gregwhitworth> fantasai: I guess, I'm not sure which one is the better option
<gregwhitworth> fantasai: the reason they were seperated was due to position may be dependant on the language where as the offset may be author messing with it
<gregwhitworth> fantasai: that means any time you want to make an adjustment you'd need to provide the offset change and which side the line is on
<gregwhitworth> fantasai: that is mostly important in vertical text where the line matters
<gregwhitworth> drott: I think we still need both values, even if you combine them
<gregwhitworth> drott: under auto | we still ahve to define rules when you combine them
<gregwhitworth> myles: thinking of them as one as a position and as offset isn't valuable because having an offset from auto isn't useful because every UA has a different auto
<gregwhitworth> myles: the pixel from the baseline to the underline is different
<gregwhitworth> myles: we're in agreement here
<gregwhitworth> myles: I do have a proposed sytax for this issue
<gregwhitworth> fantasai: in the case of the conflict, over and from-font there are three ways
<gregwhitworth> fantasai: treat from-font as 0, auto, or to take the distance from the alph baseline and compute that to a pixel
<gregwhitworth> myles: you metnioned three of them
<gregwhitworth> myles: two of them, pick a winter
<gregwhitworth> myles: third is typgographically bad - because it's defined to not be applied anywhere else
<gregwhitworth> fantasai: before we add another keyword
<gregwhitworth> fantasai: there are whole lot of complications with underlines
<gregwhitworth> fantasai: when you have inline elements that have different font sizes the position of the underline gets complicated
<gregwhitworth> fantasai: if they're aligned alphabetically you're at least setting them from the same offset
<gregwhitworth> fantasai: but if they're aligned along the central baseline you don't want the line crossing through the chars
<gregwhitworth> fantasai: if you use under, you need to go below the largest descender and those calculations aren't tightly defined in L3 and we need to think about it for L4
<gregwhitworth> fantasai: I want us to be thinking about it
<gregwhitworth> myles: are you referring to the decorator box
<gregwhitworth> fantasai: not sure which one is that, but you don't want to cross through text - the UA should be taking the descendants into account
<gregwhitworth> myles: ok
<gregwhitworth> fantasai: not sure where that brings us on this topic
<gregwhitworth> drott: can you sketch out your syntax proposal
<myles_> https://github.com//issues/3118#issuecomment-421827968
<gregwhitworth> myles: I can link to it
<gregwhitworth> fantasai: easiest for combining is auto from-font | length
<gregwhitworth> koji: how you set position of underline
<gregwhitworth> myles_: no opinion - defer to fantasai
<gregwhitworth> fantasai: the offset measure in the block axis, so it works fine for vertical text
<gregwhitworth> fantasai: if the line is on the ascender side it goes away from the alphabetical baseline based on the value
<gregwhitworth> drott: do we agree that the from-font should not be used for vertical text?
<gregwhitworth> fantasai: I don't see why not?
<gregwhitworth> drott: so we do want to use it as well?
<gregwhitworth> drott: the second point here is a bit inconsistent because we had from-font only for offset value and here it's for a base align
<fantasai> auto | from-font | [ under || [ left | right ] || <length> ]
<gregwhitworth> drott: here it's changing baseline left is equivelent to position before
<gregwhitworth> fantasai: actually I think there is something we can do
<gregwhitworth> fantasai: move font-font to the other
<gregwhitworth> myles_: so it will clobber the other
<gregwhitworth> myles_: would it be added?
<gregwhitworth> fantasai: from-font + a length?
<gregwhitworth> fantasai: you get the offset and then it's added to the length
<gregwhitworth> fantasai: I want it shifted down more
<gregwhitworth> myles_: so would auto mean 0?
<gregwhitworth> fantasai: auto currently means what the UA does?
<gregwhitworth> myles_: the property that takes the length
<gregwhitworth> fantasai: I'm not sure if the offset for left and right is 0
<gregwhitworth> fantasai: if the UA does not hide the metrics of top or bottom, left or right
<gregwhitworth> myles_: underlines are exactly on the bottom of the descenders
<gregwhitworth> koji: what about when the issue is on the baseline?
<gregwhitworth> fantasai: you're right we would have to do that
<gregwhitworth> fantasai: the underline might be 0, but the alphabetic baseline there would be an offset that is UA defined
<gregwhitworth> fantasai: auto means the UA gets to define what is appropriate
<gregwhitworth> myles_: You said they add
<gregwhitworth> fantasai: we can't have an offset of 0, it needs to be exactly on the baseline or the author has very little control
<gregwhitworth> fantasai: the offset needs to be absolute
<gregwhitworth> fantasai: underline position is something that folks will primarily use in CJK
<gregwhitworth> myles_: so if both are auto it will look good, but if you set it to 0 it jumps up
<gregwhitworth> fantasai: yes
<gregwhitworth> Rossen: so what do we resolve on
<myles_> auto | [ [ under | from-font] || [ left | right ] ]
<gregwhitworth> myles_: the grammar of text-underline-position turns into this^
<myles_> auto | <length>
<gregwhitworth> myles_: the grammar of text-underline-offset is this^
<gregwhitworth> koji: yep
<gregwhitworth> fantasai: yeah I think that's right
<gregwhitworth> drott: and the behavior if the value is from-font and then a length with offset they are added?
<gregwhitworth> fantasai: yes
<gregwhitworth> myles_: so if position is auto or from-font then they add
<gregwhitworth> fantasai: no they always add, but it resolves to the alphabetic baseline
<gregwhitworth> Rossen: Any objections?
<fantasai> auto resolves to the alphabetic baseline if the offset is not auto
<gregwhitworth> Resolved: ^
<gregwhitworth> myles_: this is text-decoration-width
<mstange> scribenick: mstange
<gregwhitworth> myles_: shows presentation
<mstange> scribenick: gregwitworth
<mstange> scribenick: gregwhitworth
<gregwhitworth> myles_: we wanted to be consistent with other things, I propose text-decoration-thickness
<gregwhitworth> Resolved: text-decoration-width is now text-decoration-thickness
<fantasai> s/things,/things, but the purpose of consistency is easy of learning, and people are clearly confused, so/
<fantasai> dauwhe, you around? wondering if we should be looping back to some of the css-inline issues
<mstange> scribenick: mstange
@litherum
Copy link
Contributor Author

The resolution:

  1. The grammar for text-underline-position becomes auto | [ [ under | from-font] || [ left | right ] ]
  2. The grammar for text-underline-offset becomes auto | <length>

And the behavior:

  1. auto / auto = what we do now
  2. auto / <length> = put it at <length> away from the baseline (aka <length> clobbers auto)
  3. under / auto = put it at the bottom of the descender
  4. under / <length> = put it at the bottom of the descender plus the length (aka <length> adds to under)
  5. from-font / auto = put it where the font says to put it
  6. font-font / <length> = put it where the font says to put it plus the length (aka <length> adds to font-font)
@litherum
Copy link
Contributor Author

Also, because I didn't have a GitHub issue for it, Resolved: text-decoration-width is now text-decoration-thickness is under this issue too

kisg pushed a commit to paul99/webkit-mips that referenced this issue Nov 6, 2018
https://bugs.webkit.org/show_bug.cgi?id=191242

Reviewed by Simon Fraser.

Source/WebCore:

Before we can implement the properties properly, we have to parse them.

w3c/csswg-drafts#3118 (comment) describes the grammar:
text-underline-position: auto | [ [ under | from-font] || [ left | right ] ]
text-underline-offset: auto | <length>
text-decoration-thickness: auto | from-font | <length>

This patch also takes the opportunity to update the grammar of text-underline-position to match the spec,
and to add an alias to the unprefixed version.

We still don't support the left and right values on text-underline-position. We should add those eventually.

Tests: fast/css3-text/css3-text-decoration/text-decoration-thickness-parse.html
       fast/css3-text/css3-text-decoration/text-underline-offset-parse.html

* WebCore.xcodeproj/project.pbxproj:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::textUnderlineOffsetToCSSValue):
(WebCore::textDecorationThicknessToCSSValue):
(WebCore::ComputedStyleExtractor::valueForPropertyinStyle):
* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator TextUnderlinePosition const):
(WebCore::CSSPrimitiveValue::operator OptionSet<TextUnderlinePosition> const): Deleted.
* css/CSSProperties.json:
* css/CSSValueKeywords.in:
* css/StyleBuilderConverter.h:
(WebCore::StyleBuilderConverter::convertTextUnderlinePosition):
(WebCore::StyleBuilderConverter::convertTextUnderlineOffset):
(WebCore::StyleBuilderConverter::convertTextDecorationThickness):
* css/StyleResolver.cpp:
(WebCore::shouldApplyPropertyInParseOrder):
* css/parser/CSSPropertyParser.cpp:
(WebCore::consumeTextUnderlineOffset):
(WebCore::consumeTextDecorationThickness):
(WebCore::CSSPropertyParser::parseSingleValue):
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::textUnderlinePosition const):
(WebCore::RenderStyle::textUnderlineOffset const):
(WebCore::RenderStyle::textDecorationThickness const):
(WebCore::RenderStyle::setTextUnderlinePosition):
(WebCore::RenderStyle::setTextUnderlineOffset):
(WebCore::RenderStyle::setTextDecorationThickness):
(WebCore::RenderStyle::initialTextUnderlinePosition):
(WebCore::RenderStyle::initialTextUnderlineOffset):
(WebCore::RenderStyle::initialTextDecorationThickness):
* rendering/style/RenderStyleConstants.h:
* rendering/style/StyleRareInheritedData.cpp:
(WebCore::StyleRareInheritedData::StyleRareInheritedData):
(WebCore::StyleRareInheritedData::operator== const):
* rendering/style/StyleRareInheritedData.h:
* rendering/style/TextDecorationThickness.h: Added.
(WebCore::TextDecorationThickness::createWithAuto):
(WebCore::TextDecorationThickness::createFromFont):
(WebCore::TextDecorationThickness::createWithLength):
(WebCore::TextDecorationThickness::isAuto const):
(WebCore::TextDecorationThickness::isFromFont const):
(WebCore::TextDecorationThickness::isLength const):
(WebCore::TextDecorationThickness::setLengthValue):
(WebCore::TextDecorationThickness::lengthValue const):
(WebCore::TextDecorationThickness::operator== const):
(WebCore::TextDecorationThickness::operator!= const):
(WebCore::TextDecorationThickness::TextDecorationThickness):
(WebCore::operator<<):
* rendering/style/TextUnderlineOffset.h: Added.
(WebCore::TextUnderlineOffset::createWithAuto):
(WebCore::TextUnderlineOffset::createWithLength):
(WebCore::TextUnderlineOffset::isAuto const):
(WebCore::TextUnderlineOffset::isLength const):
(WebCore::TextUnderlineOffset::setLengthValue):
(WebCore::TextUnderlineOffset::lengthValue const):
(WebCore::TextUnderlineOffset::lengthOr const):
(WebCore::TextUnderlineOffset::operator== const):
(WebCore::TextUnderlineOffset::operator!= const):
(WebCore::TextUnderlineOffset::TextUnderlineOffset):
(WebCore::operator<<):
* style/InlineTextBoxStyle.cpp:
(WebCore::computeUnderlineOffset):
* style/InlineTextBoxStyle.h:

LayoutTests:

* fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-underline-position-expected.txt:
* fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-underline-position.html: Update the
test for the new grammar of text-underline-position
* fast/css3-text/css3-text-decoration/text-decoration-thickness-parse-expected.txt: Added.
* fast/css3-text/css3-text-decoration/text-decoration-thickness-parse.html: Added.
* fast/css3-text/css3-text-decoration/text-underline-offset-parse-expected.txt: Added.
* fast/css3-text/css3-text-decoration/text-underline-offset-parse.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@237835 268f45cc-cd09-0410-ab3c-d52691b4dbfc
@faceless2
Copy link

I'm being picky but I think that should read "the grammar for text-underline-offset should actually be auto | <length-percentage>"

@fantasai
Copy link
Collaborator

fantasai commented Jan 1, 2020

@litherum
Copy link
Contributor Author

litherum commented Jan 1, 2020

“Zero position.” I like it.

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