Skip to content

[css-text] Allow letter-spacing to have unitless values like line-height #2165

Closed

Description

@benface

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

Activity

  1. tomhodgins commented on Jan 4, 2018

    @tomhodgins

    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?

  2. benface commented on Jan 4, 2018

    @benface
    Author

    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 tracking for CSS, vertical and horizontal spacing. It annoys me that I cannot use the same units between the two properties.
  3. tabatkins commented on Jan 4, 2018

    @tabatkins
    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.)

  4. fantasai commented on Jan 5, 2018

    @fantasai
    Collaborator

    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?

  5. Nadya678 commented on Jan 7, 2018

    @Nadya678

    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?

  6. SelenIT commented on Jan 8, 2018

    @SelenIT
    Collaborator

    @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.

  7. Nadya678 commented on Jan 8, 2018

    @Nadya678

    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?

  8. css-meeting-bot commented on Apr 11, 2018

    @css-meeting-bot
    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
  9. fantasai commented on Sep 16, 2018

    @fantasai
    Collaborator

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

  10. 19 remaining items

  11. emilio commented on Jan 7, 2020

    @emilio
    Collaborator

    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.

  12. jfkthame commented on Jan 7, 2020

    @jfkthame
    Contributor

    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.

  13. benface commented on Jan 7, 2020

    @benface
    Author

    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.

  14. jfkthame commented on Jan 7, 2020

    @jfkthame
    Contributor

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

  15. tabatkins commented on Jan 7, 2020

    @tabatkins
    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).

  16. benface commented on Jan 7, 2020

    @benface
    Author

    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.

  17. jfkthame commented on Jan 9, 2020

    @jfkthame
    Contributor

    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.

  18. emilio commented on Jan 13, 2020

    @emilio
    Collaborator

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

  19. BillGoldstein commented on Jan 15, 2020

    @BillGoldstein

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

  20. nuxodin commented on May 31, 2021

    @nuxodin

    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

  21. fantasai commented on Mar 11, 2022

    @fantasai
    Collaborator

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

  22. benface commented on Nov 18, 2023

    @benface
    Author

    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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions