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] Allow letter-spacing to have unitless values like line-height #2165

Closed
benface opened this issue Jan 4, 2018 · 31 comments
Closed

Comments

@benface
Copy link

benface commented Jan 4, 2018

Problem

There is often a need to set the letter spacing of an element to a fraction of its font size to reproduce a given design, and have it propagate down as it should (like most text-related properties, letter-spacing is inherited). That can be done with an em value, but unfortunately it breaks when the font size changes in a descendant element, because the value is computed using the font-size that is used where the letter-spacing is set.

Example:

.rich-text {
    font-size: 16px;
    line-height: 1.5;
    letter-spacing: 0.1em;
}

.rich-text h1 {
    font-size: 32px;
}

(JSBin here: https://jsbin.com/gupekikena/edit?html,css,output)

In this example, we want the letter spacing to be 0.1 times the font size. This is the equivalent of setting the "tracking" in Photoshop to 100 since "Tracking and kerning are both measured in 1/1000 em" (source: https://helpx.adobe.com/photoshop/using/line-character-spacing.html). However, that value is computed directly in .rich-text and becomes a fixed 1.6px, so in an h1, even though we set the font-size to 32px, the letter spacing is still 1.6px and not 3.2px like we'd expect. We have to duplicate the letter-spacing: 0.1em; rule every time we change the font size in a descendant to have the result we want.

Proposed solution

Introduce a new unitless value option for letter-spacing that works like line-height's unitless values. Notice in the example above, the line height is set to 1.5 times the font size, and it properly propagates down to h1 and any other descendant that changes the font size. I believe a unitless value for letter-spacing should work exactly like that. We would simply have to remove the em in the example above and it would work.

I'm aware that we can achieve this with custom properties (https://stackoverflow.com/questions/39692615/is-it-possible-to-have-letter-spacing-relative-to-the-font-size-and-inherit-prop), but I feel like it's still worth adding.

Related to #1814

@tomhodgins
Copy link

tomhodgins commented Jan 4, 2018

Hi @benface, this seems like one of the problems that CSS Variables were designed to solve for us—passing down values from a parent to its children! I'd rather embrace a solution that uses CSS features available today (using CSS Variables to their fullest) rather than expanding CSS to include new units to accomplish something that's already possible.

In this particular case of "passing down a value from a parent to its children" you want a new unit to set letter-spacing but how many other use-cases of the same "passing down a value from a parent to its children" technique that CSS Variables currently support would adding this new 'letter-spacing' unit help? Probably not that many other use cases.

So, phrased another way: How many new units would you need to add to CSS if we want to avoid using CSS Variables cases where we want to pass a value down to children?

@benface
Copy link
Author

benface commented Jan 4, 2018

Makes sense @tomhodgins, but I would add two things:

  • I'm not proposing a new unit per se; unitless values are allowed in lots of places across CSS.
  • A huge part of what bothers me about this is that it's inconsistent. I feel like line-height and letter-spacing are very closely related, they are basically leading and kerning for CSS, vertical and horizontal spacing. It annoys me that I cannot use the same units between the two properties.
@tabatkins
Copy link
Member

Note: unitless values are a new unit - they're just a lazier way of adding a new unit without actually minting a new suffix. I'm trying to avoid adding new ones in new designs, when possible - when plain numbers are actually lengths in disguise, it makes calc() dramatically more complicated. (See the third note in https://drafts.csswg.org/css-values/#calc-syntax where we talk about how it's not actually allowed - you can't add together line-height: 1 and line-height: 20px into a line-height: calc(1 + 20px) - we'd need to mint an actual unit for that to work.)

@fantasai fantasai added the css-text-3 Current Work label Jan 5, 2018
@fantasai
Copy link
Collaborator

fantasai commented Jan 5, 2018

I was thinking about this problem just the other day, and was surprised this wasn't a solved problem already. Totally agree with the premise.

@tabatkins We could use percents here. It's inconsistent with how line-height works, but imho line-height's use of percents is broken; we don't resolve them anywhere else.

An interesting question is whether the ratio should be relative to em or ch; imho we should go with em which is more fundamental, and once we have unit math calc() can be used to provide the other ratios.

So the proposal is that letter-spacing accept percentages, which inherit as percentages, with 100% = 1em on the current element.

Then there's the question of what word-spacing should do. Currently a percentage on word-spacing multiplies the width of the affected word separator character (typically a space, but some scripts use a visible glyph, Ethiopic being the main one with contemporary use). Should we keep that definition or make it match word-spacing?

@Nadya678
Copy link

Nadya678 commented Jan 7, 2018

Then there's the question of what word-spacing should do.

BTW. Why word-spacing:0px still make a gap between words? Is there solution to set no spacing between words and between inline-blocks without removing CR LF from code?

@SelenIT
Copy link
Collaborator

SelenIT commented Jan 8, 2018

@fantasai, I believe that calculating percentage from the width of the normal inter-word space is useful (one quite common use case would be removing spaces completely with word-spacing: -100%, some designs could require doubling the spaces with 100% value, etc.). I'd say that letter-spacing values relative to the inter-word space width (e.g. spacing the letters for a half of it) also would have its use cases (Photoshop is not the only design tool, after all, designing directly in browser is also quite popular), so if font-related percentages would be redefined, it would be worth reintroduce this measure as a new unit (maybe ws?) suitable for both properties, as well as for margins/paddings etc.

And what about reusing the fr unit for font-related properties? It's already a "length-but-not-exactly", it means "fraction", so it could inherit as a fraction of the font-size instead of the computed length... Is it a too crazy idea?

@Nadya678, the word-spacing property is defined as an "extra spacing in addition to the intrinsic inter-word spacing". The currently proposed (yet not supported by browsers) standard CSS way to shrink inter-word spaces to zero is word-spacing: -100%. The most common practical CSS solutions are either setting font-size: 0 to the container and resetting it for the items, or setting the word-spacing to some negative value like -0.31em (the exact value depends on the white-space character width, usually between 0.25 and 0.4em). For monospace fonts, word-spacing: -1ch should work. Another option is to use a custom font where the whitespace character has zero width (like this). However, the best way to avoid unwanted spaces between design blocks is not using inline-blocks for them at all and using Flexbox instead.

@Nadya678
Copy link

Nadya678 commented Jan 8, 2018

I thing the word-spacing: -100% or word-spacing: none is good solution for it. I know about hacks for it but I like use CSS without modyfing HTML (additional blocks, or the > closest the <, but the code is less clear to read).

BTW. The flex-box has side effects and It cannot be used in part of layouts. Also hacks has side efects like losing of antialiasing on iOS browsers (font-size:0).

doubling the spaces

Yes - for part of standard fonts it is very appreciated.

And what about reusing the fr unit for font-related properties?

How will it work? How to use the pseudo-unit for spacing?

@css-meeting-bot
Copy link
Member

The Working Group just discussed font-relative letter-spacing, and agreed to the following resolutions:

  • RESOLVED: defer this to text L4
The full IRC log of that discussion <fantasai> Topic: font-relative letter-spacing
<fantasai> https://drafts.csswg.org/css-text-3/issues-lc-2013#issue-167
<dael> github: https://github.com//issues/2165
<emilio> rune_: btw, Blink does fail the tests in https://github.com/web-platform-tests/wpt/pull/10422 for elements not in the flattened tree, at least on release.
<dael> fantasai: This was a feature request. Worth a quick look. Might have to go in L4 unless someone has a quick solution.
<xidorn> (dbaron: on, I see, yes, we enabled that in nightly)
<dael> fantasai: We can add unitless values or add % or add a united value.
<dael> florian: TabAtkins doesn't like unitless values
<dael> fantasai: word spacing the % means that character's own width.
<dael> fremy: I understand what we're doing In previous issue with cr we render because it's a control character. We render the black square.
<dael> florian: For letter spacing I feel confortable defer
<dael> astearns: Obj to defer this to text L4
<dael> RESOLVED: defer this to text L4
@frivoal frivoal removed the css-text-3 Current Work label Sep 14, 2018
@fantasai
Copy link
Collaborator

@litherum points out in #3118 that we also have this problem with text-underline-offset.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Allow letter-spacing to have unitless values like line-height, and agreed to the following:

  • RESOLVED: Add a % value to letter-spacing, word-spacing, text-decoration-width, text-underline-offset that is an inheritable proportion of font size
The full IRC log of that discussion <heycam> Topic: Allow letter-spacing to have unitless values like line-height
<heycam> github: https://github.com//issues/2165
<heycam> fantasai: there are several related issues here
<heycam> ... one is this one, another is wrt text-decoration
<heycam> ... myles raised a similar issue on that spec
<heycam> ... several places relating to text where we currently allow lengths, ems are nice in these cases, you want letter-spacing or whatever to be font size relative
<heycam> ... but they don't inherit as lengths
<heycam> ... they inherit as absolute lengths rather than a font size fraction
<heycam> ... you probably also want to calc them together
<heycam> ... %s do fulfill this role in other places
<heycam> ... other option is to add another unit like frs, that kind of represent lengths
<heycam> ... so in this case you couldn't add 1px + 5%-of-font-size
<heycam> ... the problem with %s is that right now word-spacing uses them to mean the percetnage of the width of the space character
<heycam> ... it's also reasonable, and something that should inherit as a relative thing
<heycam> ... we have abs lengths, we have some kind of proportion of width of space, and proportion of font size, and maybe come up with some other things we'd want in terms of font metrics
<heycam> ... this is an open ended question about how to solve this value
<heycam> ... for letter-spacing, word-spacing, text-emphasis-offset, text-decoration-width, ...
<heycam> ... that would allow haing a proportion of the font size and make it inheritable as a proportion
<heycam> florian: the place where we have it now is line-height, as a unitless number, which isn't great
<heycam> jensimmons: is it too late to use ems ?
<heycam> florian: yes since they will resolve down to an absolute value and inherit
<heycam> ... and it has been like that forever
<fantasai> Here's the text-underline-offset issue - https://github.com//issues/3118
<heycam> florian: continuing with unitless numbers is bad because of Typed OM
<heycam> myles: this solution sucks, but don't know of others
<heycam> TabAtkins: don't use numbers for things that aren't numbers. for new units, mint a new unit suffix, otherwise calc has troubles
<heycam> florian: is % used in these properties for word-spacing only? or in other places?
<heycam> fantasai: so far the %s are only used in word-spacing. the only imp is Gecko, and usage is very minimal
<heycam> florian: if we're not stuck on that, switching the meaning of %, and separately having a length units for the space width, that could be more consistent
<heycam> jensimmons: so use % to mean % of the current font size;
<heycam> florian: yeah
<heycam> fantasai: we already have the infrastructure for calculating %s and having them inherit as %s
<heycam> jensimmons: the other alternative is a new unit like em but different
<heycam> fantasai: yes
<heycam> ... usability wise, %s would be ideal here
<heycam> ... would be great for line-height property, but might be a lost cause
<heycam> jensimmons: would you suggest adding it to line-height?
<heycam> fantasai: line-height is the only place where % calculates just like em
<heycam> dbaron: there are other places. font-size
<heycam> ... in general, we can describe computed values the way we want to for %s, and we haven't done that mostly for length units
<heycam> florian: I think I still stand by the proposal to use % for this, and retire the use of % in word-space from its current meaning, and introduce an sp unit to mean the width of a space
<dbaron> heycam: would it be weird that 'sp' would compute down to a length like 'ch' etc.?
<dbaron> florian/fantasai disagree over what 'sp' would do
<heycam> fantasai: I could see use cases where you want either behavior
<heycam> ... tab-size is an example
<heycam> ... right now we use bare numbers for that
<heycam> ... might want to have the tab size remain constant throughout the document
<heycam> florian: for tab size it's not sized in spaces, but spaces plus letter spacing
<heycam> ... for that example it's not going to be that unit anyway
<heycam> florian: I was thinking sp would work like ch
<fantasai> https://developer.microsoft.com/en-us/microsoft-edge/platform/usage/css/word-spacing/
<heycam> florian: so letter-spacing, word-spacing, text-decoration-width, text-underline-offset -- have a % in all of those
<heycam> RESOLVED: Add a % value to letter-spacing, word-spacing, text-decoration-width, text-underline-offset that is an inheritable proportion of font size
<heycam> fantasai: for sp, word-spacing, the current behavior you do want it to inherit as a proportion
<heycam> ... e.g. maybe you want to double the word spacing, or collapse the word spacing to zero, or cut it in half
<heycam> ... and you want the proportion to inherit through
<heycam> ... so not sure if collapsing to an absolute length is useful
<heycam> ... so what we're missing here is the other type of unit
<heycam> florian: we want another thing that behaves like %
<heycam> ... only for word-space?
<heycam> fantasai: it might be useful for letter-spacing as well
<heycam> florian: let's bike shed in the issue
<heycam> ... investigate a bit more
<heycam> fantasai: confirm that Mozilla is ok with changing how they interpret %s on word-spacing?
<heycam> dbaron: I'm ok with it
<heycam> ... it would be good if there were a resolution on what the syntax for the thing we've already implemented is
<heycam> ... at the time we change the existing syntax to something else
@jensimmons
Copy link
Contributor

Using % to do this sounds a bit weird to my front-developer ear. Maybe just because it's new. Maybe because there is something weird about it. When I feel this way, I like to bounce things off other FEDs, to see what they think. So I wrote a poll on Twitter during the F2F, just to see what happens / to see if there's universal outcry of yuk, or how people react... https://twitter.com/jensimmons/status/1054309608574148610

@davelab6
Copy link
Contributor

davelab6 commented Nov 6, 2018

FWIW I think letter-spacing is today better dealt with as a font-variations-settings axis, rather than as a text/typesetting layout engine property :)

@benface
Copy link
Author

benface commented Nov 6, 2018

But not all fonts will support that.

@davelab6
Copy link
Contributor

davelab6 commented Nov 6, 2018

Also, in the twitter thread Jen instigated, I suggested "per mille of em" and have this follow up from DB

Anything that’s based on the em is fine. Permille, percent, and upm are three good examples, and are all convertable via math, although rounding is the biggest issue with conversion.

Anything that’s based on something else, the “default” instance, or “regular”, or a % of that... Anything where the Relationship between that and the em is unknown, (such as wght, wdth or slnt) those are bad, and are not interchangeable via math. Knowing the relationship between the default and the em is the biggest issue.

@decivilizator
Copy link

I will quote my tweet here (
https://twitter.com/boletrone/status/1101528134518820864):

“I proposed that CSS should honor a long-standing typographic tradition, in which:

Tracking of 17 → 17 thousandths of an em.

All professional software does it correctly.

It’s like telling astronomers they must define apparent magnitude in lux.

It shouldn’t be up for debate.”

@fantasai
Copy link
Collaborator

fantasai commented Jan 1, 2020

@decivilizator We try to avoid unitless numbers that ultimately resolve to lengths, it creates problems in calc() IIRC, and down the line can create parsing ambiguities or syntactic inconsistencies if we end up combining it with other number representations.

The advantage of using percents over a custom unit here is that they are a type of value that already exists, and get preserved distinctly from lengths during inheritance (which is the behavior we need here). But introducing a new unit such as upm is a valid alternative.

@fantasai
Copy link
Collaborator

fantasai commented Jan 1, 2020

Fixed for text-decor-4, still needs edits for css-text-4 (but that's pending merge of css-text-3 into css-text-4).

@emilio
Copy link
Collaborator

emilio commented Jan 7, 2020

@fantasai I think it's bad that this behaves differently from line-height: <percentage>. This behaves more like line-height: <number>, if I understand correctly, right?

Percentages usually resolve "as soon as possible", this breaks that rule by intentionally inheriting them like percentages rather than the resolved length.

@emilio
Copy link
Collaborator

emilio commented Jan 7, 2020

(Or otherwise this doesn't fix the bug, right?)

@emilio
Copy link
Collaborator

emilio commented Jan 7, 2020

To be clear, line-height: <percentage> computes to a <length> in all browsers:

<!doctype html>
<style>
  div {
    line-height: 100%;
    font-size: 16px;
  }
  span {
    font-size: 32px;
  }
</style>
<div><span></span></div>
<pre>
<script>
  document.write(getComputedStyle(document.querySelector("span")).lineHeight);
</script>
</pre>

Shows 16px, not 32px.

@jfkthame
Copy link
Contributor

jfkthame commented Jan 7, 2020

Not sure how I feel about this... the inconsistency is regrettable, but the proposed behavior here (inheriting as a percentage and resolving "late") is more useful than computing to a <length> and inheriting that, and expressing the value as a percentage seems better than a unitless number.

The behavior of line-height: <percentage> seems more like an unfortunate (but no doubt unchangeable) legacy misfeature than a desirable feature; it would be sad if it forever blocks us from using percentage values in a more useful way in new properties.

@benface
Copy link
Author

benface commented Jan 7, 2020

it would be sad if it forever blocks us from using percentage values in a more useful way in new properties

But are there properties where a percentage value is inherited as a percentage? I can't think of any.

@jfkthame
Copy link
Contributor

jfkthame commented Jan 7, 2020

I think that's how background-position-{x,y} works, for example?

@tabatkins
Copy link
Member

All layout-relative percentages are inherited as percentages. The problem is that I'm not sure any of them inherit by default, so you'd only see the effect if you were explicitly using the inherit value, which is quite rare.

This is probably close to a category feature: the only reason to resolve post-computed value is if you depend on layout, or have a special reason to want your resolution-reference to change as you inherit; (almost?) all of the former are non-inherited layout-related properties, while the latter is rare (like currentcolor).

@benface
Copy link
Author

benface commented Jan 7, 2020

All layout-relative percentages are inherited as percentages. The problem is that I'm not sure any of them inherit by default, so you'd only see the effect if you were explicitly using the inherit value, which is quite rare.

Yes, sorry, I meant for inherited properties. I could only think of font-size which behaves like line-height.

@jfkthame
Copy link
Contributor

jfkthame commented Jan 9, 2020

Looking back, I see that @fantasai explicitly mentioned the inconsistency with line-height back in #2165 (comment) (the original suggestion to use percentages).

Personally, I agree with the assessment that "line-height's use of percents is broken", and I don't think we should let that stand in the way of using percent more appropriately here.

@emilio
Copy link
Collaborator

emilio commented Jan 13, 2020

I think it's still a bit weird that it's inconsistent with both font-size and line-height, but...

@BillGoldstein
Copy link

Should this be accepted, I would hope word-spacing would be treated in similar fashion.

@nuxodin
Copy link

nuxodin commented May 31, 2021

The Working Draft "CSS Inline Layout Module Level 3" mentons:

The fact that percentages compute to lengths is annoying
https://www.w3.org/TR/css-inline-3/#line-height-property

I think this applies to all non-unitless values for line-height and letter-spacing, not just percentages.

To fix this behavoir, i would love a property like font-inheritance with the possible values: length, unit

@fantasai
Copy link
Collaborator

Finally got around to merging CSS-TEXT-3 into CSS-TEXT-4. :/ Edits for this issue are now also in, so closing out.

@benface
Copy link
Author

benface commented Nov 18, 2023

I just wrote a kind of follow-up to this issue, for those who are interested: #9612

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