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 property descriptors for variable fonts #2485

Closed
jfkthame opened this Issue Mar 29, 2018 · 24 comments

Comments

Projects
None yet
8 participants
@jfkthame

jfkthame commented Mar 29, 2018

Re: https://drafts.csswg.org/css-fonts-4/#font-prop-desc

According to my reading of the current spec text, in particular:

If these descriptors are omitted, initial values are assumed.

Where a single value is specified, it has the same meaning as a range with identical startpoint and endpoint

variation values applied to fonts defined with '@font-face' will be clamped to [both] the values specified in these descriptors [...]

it seems that a "naïve" @font-face rule such as:

@font-face {
    font-family: MyVariableFont;
    src: url(fonts/MyVar.ttf);
}

will result in a face that has a font-weight/stretch/style of normal, and will not use variations to implement rendering for other values of these properties. (It might use synthetic bolding and/or obliquing, just like any other non-variable font face.)

This is what Chrome currently implements, AFAICT.

However, it's not what Safari implements; if MyVar.ttf in the above declaration has a 'wght' axis, my understanding (from a colleague's testing) is that Safari will use this to render arbitrary values of the font-weight property. Only if the @font-face rule includes an explicit font-weight descriptor will it clamp the variation values applied by the font-weight property to that range.

ISTM that the Safari behavior is perhaps more author-friendly, but it conflicts with the spec text as it currently stands, and I'm not sure if it makes the interaction of @font-face descriptors with font selection (as opposed to rendering) trickier to understand/define?

So should this be considered a Safari bug (and will it be fixed to conform to the spec?), or should the spec be revised?

A further question: where the spec says

variation values applied to fonts defined with '@font-face' will be clamped to [both] the values specified in these descriptors [...]

does this clamping apply to values specified with font-feature-settings, or only to values specified in the higher-level properties that correspond to these descriptors? On the face of it, I would understand the spec text to mean that all variation values for the axis corresponding to such a descriptor are clamped (regardless of whether they're specified in font-feature-settings or as a higher-level property like font-weight); but that does not appear to be the behavior of any current browser (and I'm not sure it would actually be desirable).

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Mar 29, 2018

It would be unfortunate if descriptor defaults prevented variable fonts from being used in a simple and natural way without adding descriptors. Unfortunately the initial value for the font-weight descriptor has always been normal i.e. 400, so we can't change the initial value.

Other ways to address this:

@font-face {
    font-family: MyVariableFont;
    src: url(fonts/MyVar.ttf);
    font-weight: 1 999;
}

allows any defined weight to be used (might have to be used with font-synthesis to prevent synthetic weights outside the range of weights supported by the variable font). Having to always specify the 1 999 is a pain though.

Another option, assuming the designer has examined the font and knows the supported range (or indeed, the range they wish to have used, which may not be the same):

@font-face {
    font-family: MyVariableFont;
    src: url(fonts/MyVar.ttf);
    font-weight: 65 490;
}

and lastly, adding an auto value which (for non-variable fonts) is the same as the initial value, and (for variable fonts) is the same as the range supported by the relevant axis for that font. So:

@font-face {
    font-family: MyVariableFont;
    src: url(fonts/MyVar.ttf);
    font-weight: auto;
}
@dbaron

This comment has been minimized.

Member

dbaron commented Mar 29, 2018

Could we change the initial value of the descriptor to the auto value and make it mean normal for non-variable fonts?

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Mar 29, 2018

Oh and I guess another option is just to redefine what the initial value is, for variable fonts, so that the descriptors are only used when the designer wants to further restrict the range (kind of like unicode-range is used to further restrict the charmap).

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Mar 29, 2018

@dbaron I believe we were having the same thoughts at the same time :)

@jfkthame

This comment has been minimized.

jfkthame commented Mar 29, 2018

This suggestion:

adding an auto value which (for non-variable fonts) is the same as the initial value, and (for variable fonts) is the same as the range supported by the relevant axis for that font. So:

@font-face {
    font-family: MyVariableFont;
    src: url(fonts/MyVar.ttf);
    font-weight: auto;
}

seems problematic to me, because if auto means "the range supported by the 'wght' axis in the font", then the browser has to download and parse the resource before it can run the font matching algorithm and thus determine whether this face is needed at all.

@jfkthame

This comment has been minimized.

jfkthame commented Apr 3, 2018

I've created a testcase for behavior of the font-weight descriptor at https://jfkthame.github.io/variation-fonts/gingham.html, with screenshots (at the bottom of the page) to show how it renders in Safari, Chrome, and Edge.

AFAICS, none of the three renders as the spec currently requires, though Chrome comes nearest.

@SergeyMalkin

This comment has been minimized.

SergeyMalkin commented Apr 3, 2018

Your page suggests that Edge ignores font-weight descriptor. It is not ignored, it used for font matching. You can see WPT tests we submitted for relevant test cases. Thing that we don't do is clamping.

Descriptor play double purpose (font matching and clamping) and use cases may contradict each other. Font mapping looks more important to me than clamping. And proposed 'auto' value doesn't help here.

Clamping is fine detail of restricting actual allowed axis range. I can't imagine it used widely (on purpose)and preferred over font matching logic.

One more argument for me in favor of not doing clamping automatically is that following same logic of clamping values will prohibit browsers from applying bold or italic simulation it tons of existing pages. This looks like important breaking change to me.

If clamping scenario is considered important enough, it may deserve separate descriptor similar to font-synthesis.

@jfkthame

This comment has been minimized.

jfkthame commented Apr 3, 2018

Your page suggests that Edge ignores font-weight descriptor. It is not ignored, it used for font matching. You can see WPT tests we submitted for relevant test cases. Thing that we don't do is clamping.

Right; I should have explicitly noted that this testcase is specifically about clamping the used value of the property. I've clarified the note on the page.

@jfkthame

This comment has been minimized.

jfkthame commented Apr 3, 2018

As for whether clamping is important, and whether it should be handled by a separate descriptor rather than as the spec currently says, that all sounds like material for WG discussion. As things stand, there's a glaring lack of interoperability between the shipping implementations, which is not a good situation.

@clagnut

This comment has been minimized.

clagnut commented Apr 10, 2018

As an author, the behaviour I expected when no font-weight descriptor is supplied is for the variable font to be rendered at different weights when font-weightis applied, not for it to be clamped to font-weight:auto. The implication is that if no font-weight property is specified for the element, then the default weight should be treated as if normal (400) had been specified. (As per Safari's rendering in jfkthame's test).

Conversely if a font-weight descriptor is supplied, then I would expect clamping to be applied. At this point in time, I'm particularly thinking about this in terms of @font-face rules which could include fallbacks for non-variable fonts. Clamping weights when the font-weight descriptor is supplied provides a kind of consistency between variable and non-variable fonts in that regard.

I would expect the same logic to be applied to other descriptors too: authors include a descriptor in order to clamp (and for backwards compatibility with non-variable fonts). No descriptor, no clamping, and inherited properties are applied.

@litherum

This comment has been minimized.

Contributor

litherum commented Apr 10, 2018

Yeah, @SergeyMalkin’s explanation is totally correct. For the purpose of font selection, a missing descriptor will be used as if its default value was specified. However, once a font has been selected, and it’s time for the browser to apply variation values, a missing descriptor means “don’t clamp.” You’re right that the spec didn’t describe this, and the reason I implemented it this way is because of @svgeesus’s comment about omission of descriptors disabling variations (and that it’s unfortunate).

This is almost certainly what authors want (as @clagnut describes) and is easy to implement and spec.

@litherum

This comment has been minimized.

@clagnut

This comment has been minimized.

clagnut commented Apr 11, 2018

Just in case I'm way off, I thought it worthwhile showing how I would go about providing fallback for non-variable fonts as it stands:

@font-face {
  font-family: 'SourceSans';
  src: url('source-sans-variable.woff2') format("woff2" requires variations),
       url('source-sans-regular.woff2') format('woff2');
  font-weight: 400; 
}

@font-face {
  font-family: 'SourceSans';
  src: url('source-sans-variable.woff2') format("woff2" requires variations),
       url('source-sans-black.woff2') format('woff2');
  font-weight: 900; 
}

So in the above example the variable font should be clamped to 400 and 900 weights. But what should happen if I were to append the following rule?

@font-face {
  font-family: 'SourceSans';
  src: url('source-sans-variable.woff2') format("woff2" requires variations);
}

I think I would expect it to release the clamps.
But then if I prepended that rule instead, I think I'd expect the clamps to apply. It's possible I'm missing something about how @font-face rules cascade and override each other.

@jfkthame

This comment has been minimized.

jfkthame commented Apr 11, 2018

So in the above example the variable font should be clamped to 400 and 900 weights.

What exactly do you mean by this? As I understand it, in your example the variable font will be used only at weights 400 and 900, providing two distinct faces that correspond to the non-variable Regular and Black; it will not be used at intermediate weights. So you have two faces, each of which is "clamped" to a single weight. Was that your intention?

If you wanted the variable font's rendering to provide a range of weights from 400 to 900, you should use something like

@font-face {
    font-family: 'SourceSans';
    src: url('source-sans-variable.woff2') format("woff2" requires variations);
    font-weight: 400 900;
}

Adding your no-weight-descriptor rule provides a face that (in the Apple/Microsoft interpretation) is considered to have weight 400 for font-selection purposes, but for rendering will use whatever range of weights the variable font actually supports. (But in the Chrome interpretation -- a more precise reading of the current spec text, AIUI -- this rule is equivalent to the one with font-weight: 400.)

(Oh, and this "requires variations"... something like that has been discussed, I know, but it's not spec'd yet, is it? According to the current text, it's format("woff2-variations").)

@clagnut

This comment has been minimized.

clagnut commented Apr 11, 2018

So you have two faces, each of which is "clamped" to a single weight. Was that your intention?

Correct, although the two faces are actually the same font file for a browser supporting font variations.

"requires variations"... something like that has been discussed, I know, but it's not spec'd yet, is it?

No, not yet, but seems to be the prevailing thinking which is why I used it in the example.

@css-meeting-bot

This comment has been minimized.

Member

css-meeting-bot commented Apr 11, 2018

The Working Group just discussed font property descriptors for variable fonts, and agreed to the following resolutions:

  • RESOLVED: Add an auto keyword to the appropriate font descriptors that has the effect of the following: 1) for font selection purposes the font is selected as if the appropriate initial value is chosen. 2) for variation axis clamping, clamping does not occur
The full IRC log of that discussion <dael> Topic: font property descriptors for variable fonts
<dael> github: https://github.com//issues/2485
<dael> dbaron: The way @font-face works is what you're doing is you're adding a font-face to library of fonts browser can consider. Has descriptors, one is source, and the rest describe the thing at the end of the source. Many cases they have default values. Better to spec a font-family. If you don't do either it's 400, style default sto normal. etc.
<dael> dbaron: Useful because means the UA can decide if to download based on these things. Then we introduced variable fonts which have maybe more hten one font-weight. The interesting part is that they can have variation axes that corrispond to these descriptors.
<dael> dbaron: Spec says you're defining variable font with @font-face rule and you don't spec a weight your font is used for 400 according to the spec.
<dael> florian: Other fotns for other weights?
<dael> dbaron: I don't want to get into that part.
<dael> dbaron: You can write 4 @font-face rule and now your variation font is limited to 4 weights.
<dael> myles: Context: key problamatic pieces is descriptors are defined to take on initial value. You covered that. Other pieces is that whatever is inside those descriptors clamps the effective range and in thinital value says you clamp to a range of size 0 which is not what you want.
<ChrisL> @font-face { font-family: MyVariableFont; src: url(fonts/MyVar.ttf); font-weight: 65 490; }
<dael> myles: When I impl this in webkit I discovered this is a problem because if it was selected and doesn't have a descriptor you're forced to default value. I impl that if there's no descriptor the clamping would not occur.
<dael> myles: Spec deosn't say to do that and we're the only browser that does.
<dael> dbaron: FF doesn't ship, would like to soon, and recognizes this isn't good. But from Jonathan's understanding os webkit is that it makes it hard to figure out what to download. His impression is it interferes with the decision on what to download.
<dael> ChrisL: In font's 4 this is changed and you can give a range. BUt we don't want to force 1-999 because there's a weight axis. THat's why I proposed an auto value which gives you range for variable and single for traditional.
<Joel> myles: About opening the issue for @supports, should I create it on https://github.com/w3c/csswg-drafts? (I'm not familiar with this repo and guidelines though)
<dael> myles: If the goal is I have multiple fonts and want to download the right they're distinguished between the descriptors. If they both have the descriptors then they'll know it as the right font. So I think the problem you described isn't.
<dael> dbaron: Are there cases where font-fallback says tihs weight isn't close enough I'll fallback.
<dael> TabAtkins: No. You might synth off of it but you'll stay. If you have the bold varation use that first regardless of the weight it was declard for.
<dael> myles: Distinction webkit drawn between not present and taking initial is only relevent for when there's 1 rule that shares a family. If there's 2 rules the descriptors will be there.
<dael> TabAtkins: YOu put 2 font faces to construct a family. One is weigth 400, the other 700. You tell it to use 500 and it'l select 400 font. Will variations happen at that point?
<dael> myles: In you case bad things would happen, we'd select on of them and then we'd clampt o a 500:500 range.
<dael> myles: But if author writes a font-face urle they wouldn't write that.
<dael> dbaron: You can use fontface rules to provide part of what a font provides. You can only use a certain unicode range.
<dael> myles: That's reason for clmaping
<dael> ChrisL: You can say I only want to use a rescrticted range of what it can do. But if you don't put one in it can do waht it can do.
<dael> florian: Question. When you're doing this clamping etc. can you also have withing the variablility I was to use 200-400 but map to 400-600
<dael> myles: Different discussion. THere's a different open issue
<dael> TabAtkins: On the situation I desc a viariant font with not @font-face declaration and another with a weight. You say select the 450 does selection occur there?
<dael> myles: Yes
<dael> dbaron: Other meta point is this is a feature we've done a good job on coordinating on shipping at the same time, which is good. but that makes this high priority.
<dael> florian: Variable font dow't have a descripto and you have another on 700 and you say 450. Instead you say 699 and you still get the fist one.
<dael> TabAtkins: We should switch to auto where it means the same as the initial values but it does not cause any clmaping.
<dael> florian: When you ask for 699 it's not a range. The variable would not be matched because it's default to 400. If you drop the 400 you do the same thing. But if you're close to 400 that you would get the font you get it and draw it at the requested weight.
<dael> fantasai: If you wanted 699 off this font?
<dael> florian: You draw the range.
<dael> myles: The descriptor that covers everything is a better match.
<dael> dbaron: What TabAtkins said made sense. Does myles agree?
<dael> myles: I think that's acceptable.
<dael> dbaron: Is it waht safari does?
<dael> myles: Almost. Close. With TabAtkins proposal an @font-face block could say font-weight auto. In my impl that's a parse error.
<dael> fantasai: I still think it's a little weird that you say font range is auto which means everything and it's able to do weight 699 and we pull 700.
<dael> TabAtkins: We don't know it can do 699 so we don't download it and and won't know it can do 699 until we download.
<dael> myles: Most fonts on the web don't have variable.
<dael> ChrisL: If yousay auto you should know that it's variable since nothing is tagged as auto.
<dael> myles: Maybe they should write 0-999.
<dael> ChrisL: I'd rather an opt in keyword and not have to write the whole range.
<dael> dbaron: I'ts better to write 0-999 because you know it's a variation. I think auto where it means 400 but don't clamp is a good way to transition to the word with variable fonts.
<dael> myles: SHould authors be able to write font-weight:auto
<dael> dbaron: It'll be possible but we shouldn't suggest it.
<dael> fantasai: I agree with ChrisL it's not nice to make authors write 0-999 and give an all keyword.
<dael> myles: Most varaiable fonts don't support 0-999.
<dael> fantasai: But if authors don't want to think about it and just want 0-999 it's awk.
<dael> ChrisL: It's like for unicode where they don't write the range.
<dael> Rick: As a font user it's hard to determine range
<dael> J...: The fotns as they're developing have quite different ranges. We're only dealing with weight because it's the only variable range that maps to CSS. Maybe with font-weight we want people to put in the effort to put in the low and high because it also supports wanting to subset the range.
<astearns> s/J.../jpamental
<dael> fantasai: But the browser gets a request for 100 and the range is 200-800 I'm still going to get the font. Unless there's another font that supports 100 I'm still going to get that font and I'll use the lowest number. In terms of which file will I download it doesn't matter. Only time it matters is if there's another font that covrs the range.
<dael> myles: Let's say there's an auto and you can say font-weight:auto and it has the same value if the descriptor is missing without the clamp
<dael> TabAtkins: For matching it acts like the values we spec.
<dael> majidvp: And no clamping.
<dael> myles: prop: Add an auto keyword to the appropriate font descriptors that has the effect of the following: 1) for font selection purposes the font is selected as if the appropriate initial value is chosen. 2) for variation axis clamping, clamping does not occur
<dael> astearns: Obj?
<dael> RESOLVED: Add an auto keyword to the appropriate font descriptors that has the effect of the following: 1) for font selection purposes the font is selected as if the appropriate initial value is chosen. 2) for variation axis clamping, clamping does not occur
@dbaron

This comment has been minimized.

Member

dbaron commented Apr 11, 2018

There's also the point that we want the spec to provide authoring advice that suggests authors put the real range and not use auto. (And never explicit auto.)

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Apr 11, 2018

"appropriate" in that resolution means these three descriptors: weight, style, stretch

@jfkthame

This comment has been minimized.

jfkthame commented Apr 26, 2018

There's also the point that we want the spec to provide authoring advice that suggests authors put the real range and not use auto. (And never explicit auto.)

Just wondering, why "never explicit auto"? And if that should never be used, do we actually need an auto keyword here at all, when this case can just be represented by the absence of the descriptor?

@litherum

This comment has been minimized.

Contributor

litherum commented Apr 26, 2018

Your comment, @jfkthame, is the logic I had when implementing this. It’s what I argued for during the discussing in the CSSWG.

@clagnut

This comment has been minimized.

clagnut commented Apr 27, 2018

authoring advice that suggests authors put the real range

I'm unclear what the purpose or advantage of this would be (I'm happy to learn what I've missed - undesirable synthesis perhaps?).

They way I'd think as an author is that if I wanted the whole weight axis to be available I'd probably just stick in font-weight: 1 999 and be done with it (or leave the descriptor out altogether). This would save me trying to find out that the range in the font is actually 234-845. Yes there's sites such as Axis-Praxis which expose this info easily, and maybe font documentation too, but I'm fundamentally lazy so if I don't need to do it...

svgeesus added a commit that referenced this issue Jul 4, 2018

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Oct 22, 2018

@jfkthame does 9a6e704 satisfy your comment, or it there more to add?

@jfkthame

This comment has been minimized.

jfkthame commented Oct 22, 2018

@svgeesus

This comment has been minimized.

Contributor

svgeesus commented Oct 24, 2018

I remember that we discussed doing so, I wasn't sure if we had agreed to it. But re-reading this issue yes, we do so I have more edits to do.

@svgeesus svgeesus closed this in 36f80a0 Nov 13, 2018

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