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-fonts] font-weight: bolder and lighter are counter-intuitive #2764

Open
Wes0617 opened this issue Jun 14, 2018 · 18 comments
Open

[css-fonts] font-weight: bolder and lighter are counter-intuitive #2764

Wes0617 opened this issue Jun 14, 2018 · 18 comments

Comments

@Wes0617
Copy link
Contributor

Wes0617 commented Jun 14, 2018

I'm not sure if it will be possible with future calc() improvements, but it would be great if it was possible to write:

strong {
    font-weight: calc(inherit + 100); /*
    font-weight: calc(inherit + 200);
    font-weight: calc(inherit + 300);
    font-weight: calc(inherit + 400);
    font-weight: calc(inherit + 500);
    font-weight: calc(inherit + 600);
    font-weight: calc(inherit + 700);
    font-weight: calc(inherit + 800); */    
}

As opposed to bolder and lighter that are really hard to use and that never do what the designer wants.

Thanks in advance.

@upsuper
Copy link
Member

upsuper commented Jun 14, 2018

Allowing inherit in calc is probably a major CSS syntax change which may relate to CSS Syntax and probably CSS Cascading.

@tabatkins
Copy link
Member

There's nothing wrong with it Syntax-wise (global keywords aren't handled at that level). Handling global keywords in the middle of other properties isn't problematic either - you can already do that in font-family. (font-family: foo inherit; is fine, it refers to a font named "foo inherit".)

It's just putting keywords into calc() that's problematic right now. But grabbing the inherited value of a property via a function or something shouldn't be problematic.

@Wes0617
Copy link
Contributor Author

Wes0617 commented Jun 15, 2018

Actually, maybe it's better to have a special value like "bolder" and "lighter" that instead selects the immediately larger or lighter weights available for the current font.

In other words, font-weight: calc(inherit + 100) will have no effect if inherit is 300 and there is no 400 font-weight for the current font.

@upsuper
Copy link
Member

upsuper commented Jul 3, 2018

But grabbing the inherited value of a property via a function or something shouldn't be problematic.

I moderately disagree with this. It may not be a problem for font-weight especially given that it doesn't seem likely that we are going to extend it to a multi-value property. But it could happen that a property which currently only accepts a single numeric value can be extended to support non-numeric (computed) value, multiple values, or even be converted into shorthand. In those cases, we may have trouble to continue supporting this mechanism in those properties.

(Actually it's not even clear to me whether font-weight is going to be stuck in its current form. For example, could there be some new kind of font variation axis which supports adjusting vertical and horizontal direction weight differently, and its request becomes common so that we want to have font-weight support it directly?)

@WebMechanic
Copy link

came here via #2764 (reference)
so.. bump!

The above problem could be fixed if the bolder and lighter keywords would actually do what their name suggests; at least for variable fonts. No need for keyword handling in calc() then.

Maybe some variation of current() or inherited() could do the trick if nesting functions in calc() is supposedly easier. But that's a different story to than using an unknown variable set of bolder/lighter fonts.

Variable Fonts are a thing now!

Unfortunately neither "bolder" nor "lighter" move to the next weight variation within a variable font, but act binary as "bold" or "un-bold" aka "normal". That was fine when most ordinary fonts typically featured a binary state for normal/bold as well.

Also going bolder or lighter (font wise) within nested elements does not imply moving in steps of 100 only. A variable font could contain just three presets for its the "wght" axis using 200, 400, 600 or any other set of arbitrary numbers between 1 and 1000.
The same is true for an equivalent set of carefully crafted @font-face declarations using classic single font files.

With a fallback list of different variable fonts such as font-family: "Bahnschrift", "League Spartan Variable", "Source Sans Pro" one could build a working ramp of the proper font-weights of such fonts whilst being ignorant about what "wght" values actually exist.

Using "bolder" or "lighter" could (should) continiously select the next available weight variation.

Here each letter of the words "Fonts" and "Mood" is a set of nested <b> elements that might progressively get bolder from whatever weight <p> currently has set and eventually reaches whatever weight ("wght") the font's upper limit would be.

b {font-weight:bolder} /* life could be easy ... */
<!-- crudo ma bello -->
<p>Variable <b>F<b>o<b>n<b>t<b>s</b></b></b></b></b> R <strong>côôl</strong></p>
<p>G<b>o<b>o<b>o<b>o<b>o<b>d</b> Morning</b></b></b></b></b></p>

variable-bolder-fonts
Although the markup is ugly, the CSS remains fairly simple and intuitive.

Today I can do the same thing but with much more effort and have to use an explicit amount of nested B selectors - unlike the oneliner above. I also need to keep the ramp values at a specific start/end point or the result could look choppy when used in a possibly different context.
If <p> happens to be set elsewhere to the usual normal (400), the effect would not look as intended.

/* ... but it's not ... */
p {font: 200 2rem/1 "League Spartan","Bahnschrift","Source Sans Pro",sans-serif;}
p > b { font-weight: 300 }
p > b > b { font-weight: 400 }
p > b > b > b { font-weight: 500 }
p > b > b > b > b { font-weight: 600 }
p > b > b > b > b > b { font-weight: 700 }
p > b > b > b > b > b > b, strong { font-weight: 800 }

Using CSS properties the CSS can become simpler ...

p {--w:1 }
p b { font-weight: calc(var(--w) * 200) }

but the HTML gets even worse:

<p>G<b style="--w:1">o<b style="--w:2">o<b style="--w:3">o<b style="--w:4">o<b style="--w:5">d</b> Morning!</b></b></b></b></p>

Cheers.

@svgeesus
Copy link
Contributor

Unfortunately neither "bolder" nor "lighter" move to the next weight variation within a variable font, but act binary as "bold" or "un-bold" aka "normal". That was fine when most ordinary fonts typically featured a binary state for normal/bold as well.

And tat is the crux of the issue. bolder and lighter date from a time when:

  • CSS was vastly simpler and less used than now
  • there were no WebFonts
  • there were no variable fonts
  • CSS was seen as a set of "hints" to affect presentation, not a completer visual design system

Looking at the definition (bolder means _bolder, if available, or the same weight, but at least not lighter _) which is as close to meaningless as can be while still being somewhat testable, I would class the bolder and lighter keywords as legacy compat features only.

Achieving the desired effect using calc, though, seems like a much better approach.

@Crissov
Copy link
Contributor

Crissov commented Jan 28, 2020

With few additional tools, i. e. functions, authors could build individual stepping patterns.

:root {
  --font-weights: 100, 200, 300, 400, 500, 600, 700, 800, 900;
  --i: 4;
} 
foo, bar {
  font-weight: index(var(--i), var(--font-weights));
} 
foo {
  --i: max(var(--i) + 1, 9);
} 
bar {
  --i: min(var(--i) - 1, 1);
} 

@WebMechanic
Copy link

WebMechanic commented Jan 28, 2020

[EDIT: my memory failed me miserably onthis. See comments below about the confusion.]
@Crissov ignoring the non-existing index() function, I had mixed results with setting a var that refers to itself (--i: max(var(--i) + 1, 9);), esp. in Edge/18 - although that'll be history soon.
I just noticed min(()/max() are now supported in Blink !! 😎🥰

Sidenote> increments/decrements could/should work like counters, if we could store their value in a variable at runtime...

@tabatkins
Copy link
Member

I had mixed results with setting a var that refers to itself

Because that's not allowed and immediately causes the variable to be invalid-at-computed-value-time ^_^.

@svgeesus
Copy link
Contributor

I had mixed results with setting a var that refers to itself

Hopefully you had consistent reults i.e. that didn't work anywhere. CSS is declarative. All uses of a variable have the same value. There is no order of execution. It is no an imperative programming language.

That and other reasons (inheritance, initial value) is why 'CSS Variables' is now termed 'Custom Properties'.

@WebMechanic
Copy link

You're right of course! 🤐
I dug up the test file I confused this with.

--val: calc(2 + 2); 
--foo: calc(2 * var(--val)); /* Edge chokes */

The snippet's from a comment in an experiment I did ages ago toying with hsl() utilizing tons of calc() and var()s en masse to build basic color schemes and ramps.
Edge choked if calc() contained a var() that itself had calc() as it's only value. Very occult behaviour.

I can't reproduce this today as the above code for --foo works fine in Edge/18, and given the file's age it must have been an earlier release.

@litherum
Copy link
Contributor

litherum commented Jan 29, 2020

How about adding two new functions with the same names as the existing keywords?

font-weight: bolder(250); /* add 250 to the weight */
font-weight: lighter(250); /* subtract 250 from the weight */
font-weight: bolder; /* use the legacy behavior */

This doesn’t require a CSS-wide change.

@Crissov
Copy link
Contributor

Crissov commented Jan 29, 2020

Yes, I should have checked my made-up code better. (In actual production code, Iʼve only used very simple vars yet.) I could have tried solving it with counters or the current font weight or the actual width of 1ch instead, but I hope the general idea came across.

As for dedicated functions suggested by @litherum, why not more generic ones? For instance: increase(<amount-to-add-to-inherited-value>, <clamp-fallback>) and decrease(<amount-to-substract-from-inherited-value>, <clamp-fallback>). The fallback value would be used if the increment or decrement operation resulted in a value outside the valid range or used incompatible units. These functions would need to work anywhere calc() does and use the appropriate (partial) inherited single value, e. g. in background-position: decrease(10px, center) increase(10%, 100%);.

@WebMechanic
Copy link

coming back to @tabatkins earlier remark:

But grabbing the inherited value of a property via a function or something shouldn't be problematic.

Since multiple weights are a variable font thing anyways, I'd then suggest to use a property that already officially deals with it, instead of teaching and old dog new tricks.
With regular var()s that'd be:

font-variation-settings: "wght" calc( var(--normal) + 250);

Not sure if this is also animatable (some would certainly want that). I remember a CodePen doing that, but there might've been some JS involved - I don't remember that ;)

So if there were a "function or something", maybe sth. like this could get us much further:

font-variation-settings: "wght" calc( current() + 250);
font-variation-settings: "wght" calc( current(wght) + 42 * 100);

I have no opinion onits name, but thing is: this is a multi value property like there are many in CSS. The syntax and smartness of this "gimme the current|inherited value" function will be interesting to draft and for implementors to code :)

Cheers.

@litherum
Copy link
Contributor

As for dedicated functions suggested by @litherum, why not more generic ones?

We already have generic ones. They are calc(), +, and -. The title of this issue is “font-weight: bolder and lighter are counter intuitive.”

If a generic function is preferred, we should close this issue as “no change” because calc() already exists.

@svgeesus
Copy link
Contributor

font-variation-settings: "wght" calc( current() + 250);
this is a multi value property like there are many in CSS

Right. In particular, this sets the wght and resets everything else that font-variation-settings might have contained.

@Crissov
Copy link
Contributor

Crissov commented Jan 30, 2020

calc() is too generic, though, unless inherited, inherit, parent or something like that would be added as a local math constant (as suggested in the OP), similar to the new global math constants pi and e #4688. I think this recent development could solve the concerns initially raised by @upsuper.

Dedicated increment and decrement functions would avoid this new concept, but they would be limited to addition and subtraction, respectively, when you sometimes want multiplication or division (e g. in font size steps). In conclusion, they would probably be an inferior solution.

If a generic function is preferred, we should rename this issue (or create a new one).

@WebMechanic
Copy link

WebMechanic commented Jan 30, 2020

font-variation-settings: "wght" calc( current() + 250);
this is a multi value property like there are many in CSS

Right. In particular, this sets the wght and resets everything else that font-variation-settings might have contained.

oh, I forgot that part :/ Thanks for the heads up!
However, this should work though (not tested):

--mo-variations: "wght" 300, "xhgt" 0;
font-variation-settings: "wght" calc( current() + 250) , var(--mo-variations);

[edit typo]

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

7 participants