w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.44k stars 657 forks source link

[css-fonts] Specifying changes to parameters for fallback fonts #126

Open r12a opened 8 years ago

r12a commented 8 years ago

After another session of fruitless wrestling with fonts, i thought i should make sure (a) i'm not missing something obvious, and (b) if not, ask whether we can improve CSS.

This time i was trying to get a particular look across Mac- and Windows-based browsers. On the Mac i like the look of Helvetica Neue with font-weight set to 300 at a font size of 16px. But i can't find anything to match that in Windows standard fonts – well, i could get reasonably close, but i'd need to be able to change the font weight and the font size for a font-family name specified as a fallback.

I've never understood why, in CSS, i can't say something like

p {
    font: 'macfontname' 300 16px, 'windowsfontname' 500 18px, sans-serif;
}

This is a much bigger problem in non-Latin scripts, where glyph dimensions can vary widely from font to font at the same font-size. For example, compare the same glyphs set to the exact same font-size in Mongolian Baiti and Noto Sans Mongolian:

screen shot 2016-05-18 at 16 45 32

It's not just mongolian, this is a constant problem in arabic, and many other scripts.

And by the way, i thought about web fonts, but i can't help thinking that you should be able to just use standard platform fonts if you want to. Note that that tweaking the size/weight of such fonts would be easier than finding fonts that look good and can be used for free to cover the up to 15 languages we have on the i18n site, but also we're often dealing with multiple languages on a given page for examples etc, which also ramps up the bandwidth when using webfonts.

What am i missing?

litherum commented 3 years ago

Now that I think about it, I suppose can probably close this issue in favor of those other, more narrow issues

r12a commented 3 years ago

Wait a sec – the use cases in your new issues @litherum seem to completely ignore the original use case for this issue, which i repeated a couple of comments back. It's not only about tweaking the look of fallback fonts while web fonts are loading; it's also about setting different sizes, weights, etc depending on which system font the browser is going to use.

I read the transcript from the session yesterday, but i can't say i understand what the actual proposal is other than that it will be done via @font-face descriptors.

@literum could you, or somebody, give an example of what the syntax may look like (approximately/grosso modo) if one wants to resolve, say, the Mongolian issue i described above?

LeaVerou commented 3 years ago

@r12a Not sure how well that was minuted but I made that exact point in the call and was told that system fonts should also be declared via an @font-face rule (and local()).

jfkthame commented 3 years ago

@litherum With regard to:

I'm not sure font-size-adjust really covers this, especially for non-Latin fonts where the concept of ex-height may not be at all well defined, and there's a good chance that whatever data may be in fonts won't be appropriate to harmonize across families.

So to take @r12a's example of Mongolian, I imagine an author might want to write something like (using a hypothetical font-size-override descriptor):

@font-face {
    font-family: AdjustedBaiti;
    src: local("MongolianBaiti");
    font-size-override: 125%;
}
@font-face {
    font-family: AdjustedNotoMongolian;
    src: local("NotoSansMongolian");
    font-size-override: 75%;
}

body { font-family: AdjustedBaiti, AdjustedMongolian, serif; }

and this would use Baiti if available, enlarged to 125% of the computed font-size; or else Noto, reduced to 75%; or if neither of these are present, you'd end up with whatever serif maps to or whatever fallback finds.

font-size-adjust doesn't feel like the right tool for this, given its very specific (and Latin-oriented) definition. I suppose in theory if it were a descriptor, it would be possible to determine a font-size-adjust value for each @font-face rule that would yield the desired size relationship, but it feels really awkward.

(Maybe a solution would be an ex-height descriptor, so that you could specify an arbitrary value for a given face, to get control of what font-size-adjust will do for it even if it's a non-Latin script with no inherent "ex-height" and where the value in the font resource itself may be meaningless. Still feels like a cumbersome way to go about things, though.)

liamquin commented 3 years ago

On Wed, 2021-02-10 at 11:01 -0800, jfkthame wrote:

[...]

   body { font-family: AdjustedBaiti, AdjustedMongolian, serif; }

and this would use Baiti if available, enlarged to 125% of the computed font-size; or else Noto, reduced to 75%; or if neither of these are present, you'd end up with whatever serif maps to or whatever fallback finds.

More precisely, that would be done on a per-character basis, so if there's a character in the 2nd but not the 1st font, and the rest are available in the 1st, you get a mix. I'm not sure that anything could be done better, except that you may very well want (or need) different fallback fonts depeing on the font chosen.

There's also no way with font-face to say, if Helvetica was chosen for the regular font in this element, use Helvetica-oblique as the italic font, and if Helevetica-Oblique is not available, use serif as the font for p, not Helvetica at all.

So i think i'd prefer to see a @font-family() or @font-set() that can have a use-when: all-available property. That way multilingual documents have a much better chance of working. I don't think that affects Richard's original use case, though.

Part of what's going on here is the need to control the relationship between selecting a font and modifying text properties -- font-size, whether small caps, whether italic, colour, letter-spacing, maybe even font-stretch -- based on the selection.

-- Liam Quin, https://www.delightfulcomputing.com/ Available for XML/Document/Information Architecture/XSLT/ XSL/XQuery/Web/Text Processing/A11Y training, work & consulting. Barefoot Web-slave, antique illustrations:  http://www.fromoldbooks.org

svgeesus commented 3 years ago

I'm not sure font-size-adjust really covers this, especially for non-Latin fonts where the concept of ex-height may not be at all well defined, and there's a good chance that whatever data may be in fonts won't be appropriate to harmonize across families.

I agree. font-size-adjust was designed (in, like, 1997, by Todd Fahrner) for Latin, and also works with Cyrillic and Greek scripts. If you want to harmonize two fonts sizes for Arabic, or Hebrew, or Devanagari, then (best case) it has no benefit and (worst case) it adds irrelevant, random re-scaling which may make things worse..

svgeesus commented 3 years ago

@r12a wrote:

the use cases in your new issues @litherum seem to completely ignore the original use case for this issue, which i repeated a couple of comments back. It's not only about tweaking the look of fallback fonts while web fonts are loading; it's also about setting different sizes, weights, etc depending on which system font the browser is going to use.

I think I captured this in this comment on the new font-size issue

If that is correct I can add that third use case to the other new issues spawned from this one.

r12a commented 3 years ago

Thanks, @svgeesus. I think i'd have written:

Removing the mention of fallback, for me, makes the rules less rigid about which font(s) in the stack get the adjustment, and allows you to move fonts around in the stack as you wish, later. I think we're looking for a scenario here where the adjustments are applied to a font to fit a context, rather than to match the first font in the stack (though that's a subtle difference). It also makes the example that @jfkthame provided at https://github.com/w3c/csswg-drafts/issues/126#issuecomment-776937823 work.

I removed 'for the script being rendered' because, on reflection, this adjustment could be just as useful for, say, a situation where you want to specify an Arabic font with no Latin glyphs and a Latin font such that they look as if they match in a single piece of Arabic text containing Latin acronyms or names. This is a frequent issue for me in Arabic (naskh and nastaliq styles), as well as for other scripts.

litherum commented 3 years ago

@r12a

@litherum could you, or somebody, give an example of what the syntax may look like

Given your example:

p {
    font: 'macfontname' 300 16px, 'windowsfontname' 500 18px, sans-serif;
}

It would look something like this:

@font-face {
    font-family: 'macfontname';
    font-weight: 300;
    font-size-override: 100%; /* not actually necessary, but included for explicitness */
    src: local("macfontname-300weight");
}

@font-face {
    font-family: 'windowsfontname';
    font-weight: 300; /* this is intentionally *not* "500" */
    font-size-override: 112.5%;
    src: local("windowsfontname-500weight"); /* *this* is where you specify you want weight 500 to be rendered */
}

...

p {
    font: 300 16px 'macfontname', 'windowsfontname', sans-serif;
}
r12a commented 3 years ago

Thanks, @litherum. I thought that the existing descriptors in @font-face such as font-weight are for matching/finding fonts, rather than modifying them. Could easily be that i'm wrong? I would have expected to see something similar to font-size-override, let's call it font-weight-override to actually apply modifications to the incoming font. (So you might have both font-weight and font-weight-override in the list of descriptors.)

The value for font-weight-override would presumably be a numeric offset, such as +100, or -200, or so on? Or maybe (?) something like bolder, which i think is currently not allowed for @font-face descriptors.

With that arrangement i think you wouldn't need to add stuff to the local() argument, which i think is cleaner - you'd just have the font name, as usual. In addition, it seems odd to modify the font weight in local("windowsfontname-500weight") but to modify the font size in font-size-override.

does that make sense?

So i guess i was expecting something like this:

@font-face {
    font-family: 'harmonisedMacfontname';
    src: local("macfontname");
    font-weight: 300;
    font-size-override: 100%;
    font-weight-override: +100 /* not necessarily needed, but could perhaps be useful */
}

@font-face {
    font-family: 'harmonisedWindowsfontname';
    src: local("windowsfontname"); 
    font-weight: 300;
    font-size-override: 112.5%;
    font-weight-override: -100;  /* of course, only needed if the font comparison merits it */
}

...

p {
    font: 300 16px 'macfontname', 'windowsfontname', sans-serif;
}
svgeesus commented 3 years ago

I thought that the existing descriptors in @font-face such as font-weight are for matching/finding fonts, rather than modifying them.

These descriptors define the characteristics of a font face and are used in the process of matching styles to specific faces.

So yes, the descriptors are used for matching against - the properties (requests for styling) are matched against the descriptors (descriptions of the fonts that are available).

The descriptors typically contain values extracted from the font; but they need not do so. And the font is not automatically opened and checked against the descriptors, if that is what you were thinking.

So for example the font family name is usually the same as what the font contains - but it need not be. It is common to make the name shorter for example. And it can be something different entirely.

And the font weight is typically what the font says it is, but (for non-variable fonts) could be set to anything. I could point to a heavy, ultrabold font which is weight 800 and have the descriptor say it is weight 200, for example (not very useful, but possible). More usefully I could decide that this particular font looks heavier than it claims to be, so I could set the font-weight descriptor to 830 instead.

An issue is that, while massaging (or lying about, as some prefer to say) non-variable fonts is easy, it becomes harder for variable fonts because we are trusting the font more. A variable font with a weight axis may cover, say the range 200 to 500. I can massage this by using a font-weight descriptor of 280 500, meaning I don't want it to match for weights below 280; but if it does match, there is no way for me to say "given a weight n, ask this font for weight *a + n b**.

svgeesus commented 3 years ago

Or maybe (?) something like bolder, which i think is currently not allowed for @font-face descriptors.

Correct, it is not: auto | <font-weight-absolute> <font-weight-absolute>?

because bolder would not be describing anything (bolder than what?) so is unsuitable for a descriptor.

On the other hand bolder is fine as a property value (make this bolder than the parent, please)

LeaVerou commented 3 years ago

One issue with doing this all via descriptors even for local fonts is that @font-face is for single faces (let's leave variable fonts out for now). So, if I want to declare e.g. that if Helvetica Neue is used, I want tighter letter-spacing, I would need to declare dozens of rules, one for each Helvetica Neue face. Even just scoping it to Helvetica Neue Bold still requires several rules, especially if there are condensed and expanded faces available etc.

Also, the way matching is done in the font-family property is not the same as in the local() function. The latter requires the locally installed name, which can vary a lot, even for the same font.

jfkthame commented 3 years ago

This is why I tried to suggest in https://github.com/w3c/csswg-drafts/issues/126#issuecomment-764641927 that the place for these descriptors is in a new @-rule that addresses the family rather than the individual face. This would provide a customizable mapping from the "nominal" property values as used in the CSS to adjusted values that should be used with the specific family.

jpamental commented 3 years ago

The only way I think it will be really usable for the case that I was describing is on the selector level: meaning a specific font and usage needs this 'fallback correction' for one or more fallback font. I don't think this is helpful enough on a font family as you would need different corrections for different weights of a font (or variant in the case of italics), and applying the same correction for all uses of a single font across all selectors doesn't help either if you are using a bold weight with negative letter-spacing in a header and normal spacing with adjustments for fallbacks in body copy.

svgeesus commented 1 year ago

Related: Font styles & font fallback