w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 666 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?

duerst commented 8 years ago

I fully agree with Richard. Actually, when I saw his comment, I said to myself: How obvious; why haven't I thought about this much earlier. Combining multiple scripts on a page always requires a lot of care with respect to size and also weight. This functionality would actually also be very helpful for combining multiple fonts covering the same script. I have seen many cases where e.g. a monospace font for some program text didn't fit well with a proportional font used for the running text. The only reason that I was able to think of for why we haven't thought of such a feature until now is that with low-resolution displays, such adjustments din't work very well. But with today's high-resolution screens, they are easily possible (and all the more desirable).

tabatkins commented 8 years ago

I agree with the problem statement, it's definitely valid. But there are some issues with the proposed solution:

The third point is probably unaddressable and we just need to leave it; that's just a fallback issue anyway and shouldn't get hit by well-designed content in normal circumstances. The rest, tho, suggest that the solution is higher than the property level and probably needs to be addressed either thru @font-face, or a new at-rule better suited for constructing a composite fallback-list with control over all the aspects at each point.

litherum commented 8 years ago

My biggest worry is about how this new syntax would interact with the existing font-weight and font-size properties. It seems very confusing to have two properties which may disagree.

I do agree that the current facilities for font fallback are lacking.

r12a commented 8 years ago

It seems we're all agreed on the problem statement, and that a solution needs to be found.

To be clear, I have no attachment at all to the syntax of the example solution i included in my original post (and btw @tabatkins the 300 and 500 were meant to be weights). I just want some way to indicate that various parameters should be different as you fall back to one of the named fonts.

I think that once you get to sans-serif all bets are off. It's just a question of specifying comparative parameters for the named font families in the fallback list.

I also suspect that the alternative parameters could be specified comparatively against the first item in the list of font-family fonts, or you could have some special rule which allows you to specify absolute font sizes (for example) and that then works out the ratios for you.

upsuper commented 8 years ago

I guess @font-face might be the right way to go. Probably a new descriptor e.g. font-size-ratio can be added into @font-face to address the font size problem.

I think weight difference is already resolvable via @font-face as you can specify full font name or postscript name in local().

This could be annoying for authors, though.

r12a commented 8 years ago

i gave some thought to @font-face yesterday, and concluded that actually it does the reverse to what we want. With @font-face you specify features and it selects a font on that basis, whereas for this we want to specify a font and then select features.

I suspected that maybe we need a new at-rule such as @fallback-font-sequence which allows you to specify a number of local or embedded fonts, associate them with each other, but then establish appropriate distinctions between their features. Then the @fallback-font-sequence could be given a name, which is used in the font-family property value. (?)

litherum commented 8 years ago

I was considering the idea of allowing font-weight and font-size to take a new value which would represent a normalized weight / size. Given that we're only concerned about preinstalled fonts here, the UA would likely have the information required to perform such a normalization. This would be much simpler than introducing a new at-rule.

tabatkins commented 8 years ago

Yeah, changing @font-face is the wrong way. What you described, @r12a, is what I was thinking of.

frivoal commented 8 years ago

No need to reach for mongolian, the same happens just fine in English. Baskerville as found on OS X vs Libre Baskerville, at the same font size and same weight, are very differently sized.

I've found myself wanting to use the OS X one as a default (it's got more open type features), and the libre one as a fallback, but the size being very different makes it tricky, and font-size-adjust cannot be used to adjust only some of the fallback fonts.

frivoal commented 8 years ago

Gérard said:

Florian,

Can you explain why you believe that 'font-size-adjust' can not be used to adjust (compensate) fallback fonts. I am not sure I understand what you are saying.

3.6 Relative sizing: the font-size-adjust property https://www.w3.org/TR/css-fonts-3/#font-size-adjust-prop

In my mind, 'font-size-adjust' has been created specifically so that a fallback font (not available on a system) used size will be adjusted to match the first font of a list or to constrain all possible match of a font list to a certain size.

The glyphs will likely/possibly/probably not look the same but their relative size (aspect value) will be the same, must be the same:

http://test.csswg.org/suites/css-fonts-3_dev/nightly-unstable/html/font-size-adjust-003.htm

frivoal commented 8 years ago

Sorry, I was taking shortcuts and not explaining them well. font-size-adjust does indeed work, but it merely does the objectively thing, not the subjectively correct things.

The number you need to use for two fonts to feel the same size isn't always the same.

For instance, if you look at this example, preferably on a Mac, or on a computer that has a baskerville font with the same metrics installed: http://jsbin.com/powokig/edit?html,css,output

For those who don't have the right fonts it looks like this

screenshot 2016-05-26 14 03 37

The first p has not font-size-adjust, and is obviously terrible.

The second one has font-size-adjust applied with the same value on both baskerville and libre baskerville. It's much better, but the two fonts, while close, don't feel quite the same. Libre Baskerville has comparatively shorter capitals, and due to the shape of the glyphs, the lower case letters feels every so slightly shorter as well, even if I am sure the metrics do match.

On the third p, I am applying a different font-size-adjust for baskerville and libre baskerville, which I think makes them subjectively more similar. I can do this here because I am actually specifying the fonts separately, but if I had been using fallback fonts, there would be no way for me to do that.

In this case, the difference is tiny, and nothing to loose sleep over, but the best result isn't the one you can achieve with font-size-adjust, and I suspect that as Richard mentioned, things get worse with internationalization.

liamquin commented 8 years ago

One difficulty here is that there is no way in CSS to say whose version of a font with a given name you want. In most cases all Baskerville fonts are the same - but what if there's one with pictures of dogs in it? Traditionally the font vendor would be named, e.g. Adobe Baskerville, and often these days include vendor names in the font name, but for example on my system I have 228 variants of Helvetica, many installed by different programs. The per-glyph fallback on a site that uses Helvetica means I start with a randomy-chosen Helvetica, then might get e.g. fi ligatures from a different one. I quite often see Web sites with the fi/fl/ff ligatures obviously in a different font, for example bolder when the font names didn't fit into the CSS 100-step boldness categories.

So there are several steps, (1) choosing a base font family, which as Tab says needs some high-level work, e.g. to choose the first font family from a list, where that family has fonts to support roman and italic for a given character range along with specific other features, such as having a condensed variant, or having true small capitals; (2) choosing a base font within that font family, without wandering off into some unrelated font that happens to have the same font name but came from a different vendor or foundry (3) potentially modifying that chosen font, e.g. to simulate bold or oblique (ugh but there we go) or to condense or stretch it (some implementations do this if font-stretch is specified; others will only select a font that already exists with a corresponding font matrix (!) and at least one will simply leave blank gaps in the output where hte text shold be if font-stretch doesn't match) (4) per-character and per-glyph fallback as needed, going back to step (2) and then repeating step (3).

Right now CSS fonts doesn't seem to give clear control over these steps, leading to some odd effects such as those you (Richard) see.

Selecting based on platform is not the right approach though - e.g. Richard left out Linux or Android, and desktop macs have different fonts perhaps than iphones, as do differing versions of Microsoft Windows. And many users have fonts that are from different platforms, whether from dual booting or (probably much more often) from installing applications that in turn installed fonts. The test should be for specific versions of fonts, or at the least specific foundries an capabilities (just like writing portable C or C++ tests for features, not for platform).

duerst commented 8 years ago

On 2016/05/29 11:11, Liam Quin wrote:

Selecting based on platform is not the right approach though - e.g. Richard left out Linux or Android, and desktop macs have different fonts perhaps than iphones, as do differing versions of Microsoft Windows. And many users have fonts that are from different platforms, whether from dual booting or (probably much more often) from installing applications that in turn installed fonts. The test should be for specific versions of fonts, or at the least specific foundries an capabilities (just like writing portable C or C++ tests for features, not for platform).

I have only a vague recollection, but doesn't the X11 windowing system have information such as foundry,...? I don't think we can use that system as is, but maybe we get some additional hints out of it.

Regards, Martin.

litherum commented 8 years ago

@liamquin In WebKit, we are interested in limiting font selection of local font faces to only the preinstalled fonts (disregarding any user-installed fonts). Originally, the purpose of this idea is to combat fingerprinting, but it also sounds like such a policy would also solve your item (2). However, we're still investigating this idea; we don't know yet if it will work.

litherum commented 8 years ago

It sounds like using something like @fallback-font-sequence would associate a small set of CSS properties with each item in the font family list, where it is obvious how to apply each property in that small set to individual glyphs rather than full elements.

In the related issue https://github.com/w3c/csswg-drafts/issues/450#issuecomment-245485065 we are investigating using this mechanism to better match fallback fonts to web fonts during the download of the web font. A small set of properties suggested are: font-weight font-size letter-spacing word-spacing line-height

One thing we should consider is that, if these properties are all bundled up together into an at-rule, they don't cascade nicely. This means that if a web author wants to use an existing @fallback-font-sequence rule in a new context, but slightly modified, they would have to create a copy of the whole rule, including all the properties inside it.

litherum commented 8 years ago

In this model, we would also have to define the priority for the CSS properties inside the @fallback-font-sequence rule. Because there are no selectors, we would have to define what to do if the element already has those properties set.

controversial commented 6 years ago

Is this something we'll ever get to see in CSS?

litherum commented 3 years ago

@jfkthame @kojiishi @drott do you have thoughts on this? specifically https://github.com/w3c/csswg-drafts/issues/126#issuecomment-245708960

litherum commented 3 years ago

Edit: Whoops, @r12a proposed something very similar above

Here's a concrete proposal for this issue.

How about if you could "specialize" font property values for specific fonts. ("Specialize" as a metaphor for "C++ template specialization.") Something like:

font-weight: 400 "Helvetica" 500 "Times" 300;

to mean "Set the general font-weight to 400, but use 500 for Helvetica and 300 for Times."

These strings would be matched using the usual font-fallback string matching for @font-face rules.

There is precedent for something like this: the font-feature-settings at-rule applies font features on a per-font-fallback basis, glyph-by-glyph.

The reason why this proposal isn't an at-rule is that you want cascading to work via selectors for these things, the same way they work for normal font weights. The reason why this isn't a new property is that you want the whole package of font weights to change atomically - you don't want to accidentally forget to reset one font's weight.

The computed value wouldn't have any special smarts in it - it would be computed the same way it's computed today.

The following properties (and only the following properties) would be augmented with this new syntax:

I'm not proposing changing the font shorthand at all.

(An alternative approach would be to have these "specializations" be deltas, and have them cascade independently. So you would say something like font-weight-specialization: "Helvetica" +100; and that means Helvetica's glyphs get a 100 bump in font-weight. I think this solution is worse, however, as a bump of weight from 100 to 200 has a very different visual effect than a bump from 800 to 900. Similarly if you tried to do it as a percentage - it wouldn't look right in general. I think a better approach would be to just set the per-font weights atomically in absolute units, just like regular font-weight is set in absolute units.)

litherum commented 3 years ago

@tabatkins I think this proposal satisfies many of the points you bring up above. I'd be interested to hear your thoughts on this.

faceless2 commented 3 years ago

I think you might need commas for that syntax - I thought "good idea, nice and obvious" then realised I'd assigned 400 to Helvetica, not 500. Maybe more like:

font-weight: 400, "Helvetica" "Arial" 500, "Times" 300;

I'm also wondering about some of these

Otherwise this idea works for me, whatever that's worth.

nigelmegitt commented 3 years ago

I've experienced this problem practically with line-height recently, and it certainly seems to be a very real issue. Font 1 has ascent + descent + line gap equivalent to 1.2em, font 2 has them equivalent to 1.33em. I want to specify a line-height, not just use normal, but the value I want to specify depends on the actual font used. So +1 to this proposal, including line-height.

liamquin commented 3 years ago

On Thu, 2021-01-21 at 01:09 -0800, Mike Bremford wrote:

font-weight: 400, "Helvetica" "Arial" 500, "Times" 300; This is starting to look like CORS headers, which are notoriously difficult to get right.

I'm also wondering about some of these [...]

You can for sure add font-variant (if there's a small caps font in which lower case letters render as small caps, convert to lower case and use it, otherwise if the OpenType small caps are available, use htem, otherwise convert to all caps), and font-features, where stylistic set 1 might do something entirely unacceptable in Arial compared to Helveica.

Of course, i might prefer to say "use the first font family that has a roman and an italic with small caps for the roman and support for the historical ligatures feature" which is massively more useful than tryingto do it backwards based on a list of font names, especially when there are 57 varieties of Helvetica and i'd want different letter spacing depending on which one is used, but CSS doesn't expose the font foundry or font version.

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

jpamental commented 3 years ago

This would actually solve a huge problem in better managing the user experience during the font loading process. Being able to specify all of these things (including letter- and word-spacing) would allow for better tailoring the experience of how the page renders before and after the web fonts load by allowing the spacing to be different for the intended font versus the fallbacks.

Currently this is only possible by using a web font loader of some kind in JS that would inject a class in the page like wf-inactive and then remove it once the fonts have loaded. When that class is present, you can style the fallback font differently to more closely match the metrics and spacing of the intended web font, thus minimizing the reflow of content and layout when the web font loads.

While font-display: swap is helpful in getting content on screen faster, it does nothing to help enable the above. If we had a native CSS way to do that (by being able to specify small differences in font-size, line-height, letter-spacing, and word-spacing) we could eliminate the need for a JS dependency and render pages faster and with less repainting necessary.

Here's an example of how this looks (as the current 'state of the art', mainly unchanged since 2010)

p {
  font-family: "Work Sans", Arial, sans-serif;  
  font-size: 1rem;
  line-height: 1.4;
}
.wf-inactive p {
  font-family: Arial, sans-serif;
  font-size: 1rem;
  letter-spacing: 0.035em;
  line-height: 1.375;
}

These small changes can reduce or eliminate reflow of content during the font loading and re-rendering process and has a tremendously positive impact on both user experience and overall perceived performance.

With the new syntax I could eliminated loading FontFaceObserver.js and a bunch of inline JS to manage that process, and then reduce the amount of CSS necessary, looking something more like this:

p {
  font-family: "Work Sans", Arial, sans-serif;  
  font-size: 1rem;
  letter-spacing: "Work Sans" 0, Arial sans-serif 0.035em;
  line-height: "Work Sans" 1.4, Arial sans-serif 1.375em;
}

This would help address a very long-standing issue in a far better way than ever before possible (I'm referring to FOUT: Flash of Unstyled Text. This would take the 'U' out of it entirely)

jfkthame commented 3 years ago

Personally, I'm not keen on the more complex forms being suggested for properties like font-weight, letter-spacing, etc., with lists of specific per-family values to be applied. It feels to me like it would become quite cumbersome and hard to maintain.

So I'd like to suggest an alternative approach: how about a new @-rule that lets the author create a "virtual" font-family that maps to an existing family, with adjustments that are applied to the computed values of the various rendering properties. This is a bit like the use of @font-face with src:local to in effect "rename" an installed font and specify (override) its inherent stylistic attributes, but rather than defining individual faces (perhaps many of them, to make up an entire styled family), we're mapping a new family name onto an existing family, while applying adjustments to the rendering.

Something along the lines of:

@adjusted-font-family {
  font-family: AdjustedTimes;
  base-family: Times;
  font-size-factor: 1.2; /* or a percentage? */
  font-weight-mapping: 100 100, 400 400, 500 600, 900 1000;
  font-stretch-mapping: 0% 25%, 100% 100%, 200% 150%;
}

This would mean that if "AdjustedTimes" is found in the font-family list, we use the "Times" family, but apply the given adjustments to the computed values of the associated style properties. For size, multiplying by a simple factor is probably sufficient; for properties like weight and stretch, the idea is that we can list the desired mapping for one or more values, and intermediate values will then be interpolated. So the example here leaves font-weight values up to 400 untouched, but weights from 500 up have an extra 100 added to them; for font-stretch, the default (100%) value is untouched, but both narrower and wider values are brought closer to the middle of the range.

If the given base-family is not available, the rule is just ignored.

Using such an @-rule, an author can tweak the weight, stretch, size, etc., of a standard font to more closely match a webfont that will eventually be used, and then add the "adjusted" family as fallback for the font-family property.

(This is currently just a sketch of an idea, not worked out in detail; comments welcome.)

jpamental commented 3 years ago

I think that the challenge with a 'single mapping' approach of an @-rule is that the mapping might not be universal or consistent based on usage. If you set a heading with negative letter-spacing on the intended web font, that letter-spacing value may differ for the fallback fonts from what might be specified normally. At least for the use case I outlined above, there would be too may places where a universal solution would fall short I think.

jfkthame commented 3 years ago

ISTM you can solve that easily enough by defining a couple of "adjusted font families" to use as fallbacks for your webfont; one to use on body elements and another for headings.

(As an aside, I'm not really convinced it's worthwhile to try and refine this stuff to such a degree. Fallbacks are just that: fallbacks. They may or may not even be available on a given user's system; you might end up with some other default/generic anyway. They aren't expected to render identically to the target webfont, no matter how many knobs we provide to tweak them. After all, if they did provide a perfect substitute, why use the webfont at all? So while I can see a case for some controls here, I think we should avoid getting too carried away...)

drott commented 3 years ago

Personally, I'm not keen on the more complex forms being suggested for properties like font-weight, letter-spacing, etc., with lists of specific per-family values to be applied. It feels to me like it would become quite cumbersome and hard to maintain.

I agree with that.

Jonathan, I think @xiaochengh, @chrishtr and I were talking about a similar approach to what you were drafting when talking about the ascent-overrides, etc. - One thing we talked about were potential issues with how specific the from-to mapping is if only using a font family name:

In your example, would base-family: Times; refer to a web font, a system font, or both?

In some cases, common system font families like Times are sometimes not available on a system and then mapped to other fonts, like Tinos, or for Arial, mapped to Deja Vu Sans on Linux for example. So it's a bit tricky to uniquely identify the intended base. One idea I had was to use something like base: local(<PostScript or full font name>) in that case, but that would not work for web fonts. Alternatively, some kind of link-id could be used. (Also, only very raw ideas so far).

jfkthame commented 3 years ago

Personally, I'm not keen on the more complex forms being suggested for properties like font-weight, letter-spacing, etc., with lists of specific per-family values to be applied. It feels to me like it would become quite cumbersome and hard to maintain.

I agree with that.

Jonathan, I think @xiaochengh, @chrishtr and I were talking about a similar approach to what you were drafting when talking about the ascent-overrides, etc. - One thing we talked about were potential issues with how specific the from-to mapping is if only using a font family name:

In your example, would base-family: Times; refer to a web font, a system font, or both?

I was thinking it would refer to whatever font-family: Times resolves to -- which I was assuming would be a system font, but there's no reason (afaics) this couldn't work with webfonts as well.

In some cases, common system font families like Times are sometimes not available on a system and then mapped to other fonts, like Tinos, or for Arial, mapped to Deja Vu Sans on Linux for example. So it's a bit tricky to uniquely identify the intended base. One idea I had was to use something like base: local(<PostScript or full font name>) in that case, but that would not work for web fonts. Alternatively, some kind of link-id could be used. (Also, only very raw ideas so far).

PostScript or full font name doesn't work here, because that identifies a specific face; in this case, I want to refer to a family.

I think if someone has a font configuration where common font family names are resolved to different fonts (that aren't a good design/metrics match), that's on the user, and they should be used to seeing things that look rather different than designers intended. E.g. if font-family: Arial is being substituted with DejaVu Sans, content is going to be rendering larger than authors expected all over the place.

jpamental commented 3 years ago

The purpose of what's being proposed is to help even out the user experience of 'web page loads, then web fonts load'. There are a few things that seem worth pointing out:

  1. Web fonts get a lot of use, and it only continues to grow
  2. CSS supports a lot of typographic features, which is good—because good typography improves the user experience
  3. There will always be a potential gap between when the DOM is loaded and the page initially rendering and when the web fonts load triggering a repaint
  4. We currently have no way of addressing this without adding JS

While none of these solutions will every be 100% perfect, what @litherum and @r12a proposed would give web authors far more control with far fewer dependencies.

@jfkthame The solution that I described above (the current practice using an 'inactive' class) is something that I've been using with clients since 2010, and really does make a huge difference in getting content on screen with minimal reflow. It doesn't have to be perfect; just getting it close has a massive perceived performance benefit.

Adding a capability to achieve this on a per-selector basis without requiring additional JS will enable better user experiences and better performance (by reducing the need to load/process JS).

I realize that I'm (very) biased towards the importance of web fonts, but I'm not alone there either. If authors don't want to bother, things will just work as they do now and maybe for them that's just fine.

But for those of us whose job it is to design and implement great experiences, these capabilities are really important. I've helped incorporate solutions that utilize these techniques for both the State of Georgia and now Rhode Island, and it's having a very positive impact for millions of people every week. It really makes a difference.

xiaochengh commented 3 years ago

Let me add one more dimension to the discussion: is it easy to adopt the new syntax?

One of the reasons we proposed @font-face descriptors (ascent-override etc) is that, web font services can put all the change parameters in the style sheets they provide, while web authors only need to make minimal changes to adopt (something like changing font-family: webfont, fallback to font-family: webfont, adjusted-fallback).

It seems that we cannot achieve the same using properties? In particular, we need a different set of parameters for each combination of font size, weight, style, etc. So it seems impossible for web font services to provide a complete set of parameters.

On the good side, for pages already using JS & inactive classes, it is straightforward to transition to the list syntax (as shown in @jpamental's comment). So whether the list syntax is easy to adopt really depends on how widely web authors are already tackling the issue with JS & inactive classes (which I don't have any idea...).

chrishtr commented 3 years ago

Another reason to prefer @font-face descriptors is that they integrate perfectly into the existing browser mechanisms for choosing fallback fonts, which is important for an ergonomic and efficient approach that avoids the need for JS polyfills.

svgeesus commented 3 years ago

@r12a this issue is on the agenda for the 9 February virtual f2f, would you be available to call in? https://wiki.csswg.org/planning/virtual-winter-2021 The meeting is 15:00 to 18:00 your time.

svgeesus commented 3 years ago

This is a particular instance of the general issue that stylesheet authors want to have:

some-selector {
  if (condition1) {
    property1: value1;
    property2: value 2;
  else if (condition2) {
   property1: value3;
   property2: value4;
   property3: value5
   }
}

This is not a syntax proposal. I'm saying that people need to assign atomic groups of property-value pairs conditionally (in this case, the condition is which font is actually used).

tabatkins commented 3 years ago

Looking over the proposals here, I believe I'm still the most in favor of adding descriptors to @font-face that "adjust" the used values of the various font-related properties when that font is the primary font for a text run. Aka what @jfkthame suggested in https://github.com/w3c/csswg-drafts/issues/126#issuecomment-764641927, just folded into @font-face itself rather than indirecting thru a new rule. (In particular, I like their "interpolate for in-between values" part.)

The most relevant factor for me in choosing this vs Myles's suggestion of putting these per-font adjustment into the property syntax (https://github.com/w3c/csswg-drafts/issues/126#issuecomment-764183953) is whether these adjustments are likely to be common to every use of the font on a page (and thus best to fold into a single at-rule) or specialized/distinct for particular uses (and thus best to target to the exact usage).

If they're likely to be common, then using per-property means a lot of repetition, and it's easy for these declarations to grow out of sync with each other over the lifetime of a page. If they're likely to be specialized, then using at-rule means you'd need to create several distinct @font-face rules, one for each specific instance, which feels pretty clumsy.

I think it's more likely for the adjustments to be common to the page, but that's just based on my intuition.

r12a commented 3 years ago

@r12a this issue is on the agenda for the 9 February virtual f2f, would you be available to call in?

yes. Addison may also come.

jfkthame commented 3 years ago

Looking over the proposals here, I believe I'm still the most in favor of adding descriptors to @font-face that "adjust" the used values of the various font-related properties when that font is the primary font for a text run. Aka what @jfkthame suggested in #126 (comment), just folded into @font-face itself rather than indirecting thru a new rule. (In particular, I like their "interpolate for in-between values" part.)

The trouble with folding this into @font-face is that an @font-face rule is specific to just one face, not to a complete font family. In the case of a variable font, where "all the faces" are in effect expressed in a single @font-face rule with range descriptors, that's fine, but it could become very cumbersome if you want to adjust the parameters used by a fallback family that has numerous separate faces.

tabatkins commented 3 years ago

Ah whoops you're right, this should instead be similar to @font-feature-values, which applies things family-wide.

chrishtr commented 3 years ago

I think there should be an ability to do it per font-face, because the parameters such as advance overrides/letter-spacing might vary by font face within the same family.

jpamental commented 3 years ago

The corrections definitely have to be applicable to a specific font and set of fallbacks, rather than a whole font family; that's the only way for it to apply in an appropriate way. Every font might have different corrections (bold versus italic versus a condensed width).

As for @tabatkins 's thought that the adjustments are common to all usage of a font across the page, I'll just say again that in the way I've used an inactive class to style fallback fonts, it has varied by selectors. I might use a bold font weight for bold text in a paragraph (where it might have corrections that inherit from the p tag) and also use the bold font for headings that might need different letter-spacing values. So in how I use it, it is something I do quite regularly (vary by selector, not universally for a font).

tabatkins commented 3 years ago

Interesting. So are you using different 'letter-spacing' values to start with on those instances, or are they intended to be the same 'letter-spacing' value, but they need different nudges to look right at each size?

I ask because the first case can be handled by @jfkthame's suggestion, where you can map different ranges of each property to different values, but the second really does require per-use adjustment.

chrishtr commented 3 years ago

See also issue #5533 for overrides to spacing between glyphs (the advance of the glyph, actually).

jpamental commented 3 years ago

@tabatkins Here's an example that sort of case:

A heading might be set in the bold weight of a font, larger, and with a small amount of negative letter-spacing. So a fallback for this would need specific 'fine-tuning' of size, line-height, and letter-spacing

The bold weight of the font might also be used simply for bold text in the body. In this case, the bulk of the corrections might be applied on the p tag, but there may be adjustments on strong as well (or conversely might not need any letter-space adjustments when applied at a smaller size). This is also sometimes useful if I'm styling an initial letter or line (like bolder small-caps for the first line of a paragraph).

So I will typically have CSS for a number of selectors (headings, body copy, possibly navigation items and classes), with specific fallback 'fine-tuning' for each.

My goal is mainly focused on the first 'screenful' of content, so I'll spend time adjusting selectors to minimize reflow in the header, navigation, and at least the first few paragraphs of content.

If you look at the NY Times site on an individual article, you'll often see dramatic reflow of headings even in their app as the web fonts load: nyt_fout

With these kinds of loading strategies in place, I've been able to almost eliminate that here on the RI COVID site: covid_fout

liamquin commented 3 years ago

On Fri, 2021-02-05 at 08:20 -0800, Jason Pamental wrote:

@tabatkins Here's an example that sort of case: So a fallback for this would need specific 'fine-tuning' of size, line-height, and letter-spacing

A related question is that you might want to say, a fallback font must have a matching italic and be such-and-such a weight and maybe support such-and-such a language or character range (no spindly é in the middle of regular text!).

So that suggests an @font-family or @font-set (potentially defining multiple related families) might be worth exploring.

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

LeaVerou commented 3 years ago

Yet another vote on the prominence of the use case. I always apply tight letter-spacing to bold Helvetica, which looks bad with a fallback font.

Here's another idea, with minimal syntax additions and no new microsyntaxes or tweaks to individual property grammars:

We have already more or less resolved to add inline conditionals (#4731, #5009) with IACVT behavior whenever needed.

What if we add a keyword that resolves to the currently used font-family? E.g. currentFontFamily or current-font-family or current(font-family) (TBB). Similarly to em values and currentColor, it would resolve as the inherited current font-family on the font and font-family properties, to prevent cycles.

Then authors can write conditionals to their heart's content, to do things as simple or as complex as they wish.

E.g. the example from above:

font-weight: 400 "Helvetica" 500 "Times" 300;

would be written as:

font-weight: if(current(font-family) = "Helvetica", 400, if(current(font-family) = "Times", 500, 300));

Or even, just for the lulz:

font-weight: calc(300 + if(current(font-family) = "Helvetica", 100, 0) + if(current(font-family) = "Times", 200, 0));

This provides maximum flexibility, while still allowing simple cases to remain simple. It can get a little repetitive when you need to vary many properties by the same condition, but that can be addressed via preprocessors until it's addressed more generally in CSS.

Furthermore, this means the syntax would benefit from any future improvement to conditionals, e.g. switch() or block conditionals.

css-meeting-bot commented 3 years ago

The CSS Working Group just discussed Specifying changes to parameters for fallback fonts, and agreed to the following:

The full IRC log of that discussion <gregwhitworth> Topic: Specifying changes to parameters for fallback fonts
<chrishtr> q+
<astearns> github: https://github.com/w3c/csswg-drafts/issues/126
<gregwhitworth> chris: the general principal is wanting to change things based on which font was actually used
<gregwhitworth> chris: so you set them conditionally, they expect a simple syntax. Much of this thread is to say that most simple solutions are not going to work
<astearns> ack chrishtr
<gregwhitworth> chrishtr: I wanted to point out a few things
<gregwhitworth> chrishtr: which syntax would be used
<gregwhitworth> chrishtr: main usecase that xiaochengh had in mind was automatically overriding when you have a fallback of a webfont you want to limit jumping of the webpage and add little to not difficulty to the author because it behaves automatically
<leaverou> q+
<gregwhitworth> chrishtr: the one alternative is to have a CSS property that has augmented syntax and I think that would end up being quite complex because it would need to repeat
<astearns> ack leaverou
<gregwhitworth> leaverou: there have been many proposals, they seem to revolve around changing the font-props
<gregwhitworth> leaverou: the syntax would get quite complicated
<gregwhitworth> leaverou: rather than change props let's add inline conditionals based on prior resolutions of inline conditionals
<gregwhitworth> leaverou: you can then branch however you want and it only gets as complicated as the author needs it to be
<gregwhitworth> leaverou: so you can end up with multiple font-families in a single element
<drott> q+
<gregwhitworth> leaverou: you don't want a different letter-spacing for every glyph for example
<gregwhitworth> leaverou: this gets future improvements for conditional syntax
<gregwhitworth> myles: one of the args against my proposal was unreadable and I think this may be more unreadable
<astearns> ack drott
<gregwhitworth> astearns: that would depend on the general usage but yes more flexibility usually adds complexity to parse
<gregwhitworth> drott: would you add a way to selector for the inline font?
<gregwhitworth> leaverou: no a keyword, such as accentColor
<gregwhitworth> leaverou: I can drop a link to the proposal
<leaverou> https://github.com/w3c/csswg-drafts/issues/126#issuecomment-775990597
<leaverou> s/accentColor/currentColor/
<xiaochengh> q+
<drott> q+
<gregwhitworth> astearns: I'm thinking this is a good thing to get too, but this more immediate need a descriptor rather than waiting for a solution to the conditional styling
<astearns> q?
<gregwhitworth> myles: in the last issue we were going to add one of these degrees of freedom to the descriptor
<gregwhitworth> myles: as a more concrete proposal should we try to add 4 additional descriptors to ensure alignement?
<chris> q?
<astearns> ack xiaochengh
<gregwhitworth> xiaochengh: the proposed syntax of this property is complicated and the implementation will be complicated too
<drott> q-
<astearns> ack fantasai
<gregwhitworth> xiaochengh: I'm not sure how to implement that in Chrome to be honest
<gregwhitworth> fantasai: I think going with the descriptor is a much better way than trying to embed this in font properties especially so many CSS calculations depend on those properties
<gregwhitworth> fantasai: properties are really weird to bind font-face to some value
<myles> q+
<gregwhitworth> fantasai: we can't just put it into the font-face rule, you'd want different styles to different elements, we're going to have derivitives of the same font-face with different overrides
<gregwhitworth> fantasai: it would be good to cascade in so you don't have to repeat them
<gregwhitworth> myles: so inheritance for at rules?
<leaverou> q+
<gregwhitworth> fantasai: cascading rules which is what counter style does
<gregwhitworth> fantasai: I support jonathan's proposal overall
<astearns> ack myles
<fantasai> jfkthame's proposal https://github.com/w3c/csswg-drafts/issues/126#issuecomment-764641927
<gregwhitworth> myles: one of the degrees of freedom is font-weight and that is a matching property
<gregwhitworth> myles: so if we want to have an override I'm not sure how that would work
<florian> q+
<cbiesinger> q+
<cbiesinger> hm
<cbiesinger> qq+
<gregwhitworth> myles: what that should mean is that that element shouldn't select the defined font-weight
<drott> q+
<gregwhitworth> chris: that shouldn't impact matching
<astearns> ack cbiesinger
<Zakim> cbiesinger, you wanted to react to myles
<chris> q?
<gregwhitworth> christian: could you solve that issue by having a font adjustment factor, so if the fallback is used you can multiply by something like 0.9
<cbiesinger> q-
<gregwhitworth> myles: so if you fallback to font-x use a factor of .8 or .9 for font-y
<gregwhitworth> myles: I think that's what chris was saying
<gregwhitworth> fantasai: would that work with variable fonts?
<gregwhitworth> myles: no it wouldn't work for var fonts
<gregwhitworth> fantasai: jonathan's solution has a mapping table
<gregwhitworth> florian: font-weight is the odd one here
<astearns> ack florian
<gregwhitworth> florian: they're not really numbers they're a way to match a font that happens to map to numbers
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<myles> q+
<gregwhitworth> florian: if we're dealing with variable fonts we need to map to ranges or series
<gregwhitworth> florian: the others are actual measurements, this one is weird
<gregwhitworth> leaverou: I want to say we're discuss two orthogonal issues and one is trying to provide a better fallback and one trying to improve styling for ones that were selected for fallback
<drott> q-
<gregwhitworth> leaverou: there are usecases that are local fonts eg: Mac vs Windows fonts
<gregwhitworth> myles: the folks we've talked with are fine with font-face being used
<astearns> zakim, open queue
<Zakim> ok, astearns, the speaker queue is open
<TabAtkins> ScribeNick: TabAtkins
<TabAtkins> myles: There are these props we're interested in
<TabAtkins> myles: weight, size, letter-spacing, word-spacing, line-height
<TabAtkins> myles: line-height might be taken care of by ascent/descent-override
<TabAtkins> myles: letter-sacping resolved in last issue
<TabAtkins> myles: font-weight sounds hard, need more time
<TabAtkins> myles: but font-size and word-spacing, maybe we could make progress
<TabAtkins> jfkthame: font-stretch?
<TabAtkins> myles: could be. would you like it to be?
<TabAtkins> chris: yeah, condensedness should be in the list
<florian> q+
<TabAtkins> astearns: Wondering if we should have a general reoslution to solve these things as @font-face descriptors, and start getting spec text for this
<leaverou> q-
<chrishtr> Agreed on font-face resolution being a good next step.
<chrishtr> And then discuss types of overrides.
<TabAtkins> astearns: For previous issue, for the simpler things here, and then ahve separate issues for each type of override
<TabAtkins> astearns: This is alread a giant issue that tends to spin out into overlapping convos
<chris> Yeah that sounds like a plan
<astearns> q?
<TabAtkins> florian: A discussion over the break: instead of specifying the amount you want to adjust the font, specify the target amount
<TabAtkins> florian: UA could adjust automatically, but could be flexible with variable fonts, etc
<TabAtkins> florian: Or choose different fallbacks with better metrics
<fantasai> TabAtkins: That might work for some things, but I can't see how it would work for advance
<TabAtkins> myles: It'd be an overall tracking value, like "make the average character width X sized"
<TabAtkins> jfkthame: Too many questions there, how to average?
<TabAtkins> florian: Not harder than just using the adjustment
<fantasai> TabAtkins: Disagree
<fantasai> TabAtkins: Current proposal only adjust the fallbacks.
<fantasai> TabAtkins: Take the good font, then load fallback and tweak it until to works
<fantasai> s/works/works the way you want
<TabAtkins> myles: This is why I opened an issue for font-size-adjust:auto
<TabAtkins> myles: Right now author needs to guess
<fantasai> TabAtkins: At least you can guess and check for font-size easily, but see your point in general
<TabAtkins> myles: So suggested we have an auto for that
<astearns> ack fantasai
<astearns> ack florian
<TabAtkins> fantasai: There was discussion about reoslution
<TabAtkins> fantasai: proposed resolution is to address these use-case with descriptors
<TabAtkins> fantasai: Don't think we can be more specific atm
<TabAtkins> fantasai: I know Chrome wants to address the advance-override case sooner rather than later, so we should make progress on making that concrete
<TabAtkins> astearns: So resolve the general descriptor, and specifically add advance-override
<TabAtkins> fantasai: in Fonts 5?
<TabAtkins> myles: yeah
<TabAtkins> astearns: objections?
<TabAtkins> jfkthame: Not quite sure we know what advance-override means yet - details tbd?
<TabAtkins> astearns: Yes, we resolve to add it, can spin out issues to nail down details.
<TabAtkins> RESOLVED: Solve the general case of fallback font adjustment via @font-face descriptors
<TabAtkins> RESOLVED: Add advance-override descriptor to Fonts 5, precise details TBD
r12a commented 3 years ago

As an aside, I'm not really convinced it's worthwhile to try and refine this stuff to such a degree. Fallbacks are just that: fallbacks. They may or may not even be available on a given user's system; you might end up with some other default/generic anyway. They aren't expected to render identically to the target webfont, no matter how many knobs we provide to tweak them.

What follows may be a slightly philosophical point.

I'm glad to see how the ideas here can also be applied to fallbacks related to web fonts, etc. I just didn't want to lose sight of my original problem, which was: There are very few Mongolian fonts, but pages on Windows will have guaranteed access to Mongolian Baiti, and pages on OS X will not have access to Baiti but will have access to Noto Sans Mongolian. The problem being that the metrics of these fonts on display are very different. So i just wanted a simple way to be able to say: If the browser is using Baiti, use these additional settings for font size, density, etc; if the browser is using Noto, use these other settings. So it's a use case that doesn't attempt to make the font look alike, but does attempt to produce something that takes up the same amount of space and works well for readability. In this sense, this is a slightly different kind of 'fallback' behaviour in that you actually pretty much know which font is likely to be used in which case. Solving that issue will be very useful for working with non-Latin fonts.

jpamental commented 3 years ago

@r12a I'm completely in agreement with you!

My use case is essentially the same: I want to make sure that the type fits in the same space to avoid reflow or massive amounts of repaint. Having it look the same (mimicking x-height for example) is not really important to me. I just want things to stay in the same place so if no web fonts show up, the integrity of the design/layout is maintained. And if they do eventually show up, nothing moves around.

In this way, both circumstances benefit!

litherum commented 3 years ago

A solution that utilizes @font-face descriptors isn't just for web fonts - @font-face blocks can use src: local(...) to represent local fonts, too.

litherum commented 3 years ago

Alright, I've broken up this issue into individual pieces, as per the discussion at the F2F: