Skip to content

Experiment with a non-centenary font weight #65

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

Closed
gnprice opened this issue Apr 14, 2023 · 10 comments
Closed

Experiment with a non-centenary font weight #65

gnprice opened this issue Apr 14, 2023 · 10 comments
Labels
a-content Parsing and rendering Zulip HTML content, notably message contents a-design Visual and UX design

Comments

@gnprice
Copy link
Member

gnprice commented Apr 14, 2023

Flutter supports specifying what font weight to use for text.

The main API for this, FontWeight, provides the weights 100, 200, etc., up to 900. (For example FontWeight.normal is an alias for weight 400, and FontWeight.bold is 700.)

That's plenty for many purposes, but one sometimes wants finer control with a weight like 450 or 550. In particular @terpimost would like to have the design flexibility to use such weights. Some discussion in chat.

It looks like we should be able to accomplish that using TextStyle.fontVariations. That allows specifying an arbitrary weight, as a number, by using design axis wght.

  • In fact one can even use that to drive the weight with an animation, if you want; example here.
  • The docs suggest this feature is there for the sake of variable fonts. Probably it works fine even if the font isn’t variable, though, as long as you pick a weight the font does have.

So it would be good to try that out and demonstrate that it does indeed work.

In order to successfully carry out the experiment, we'll need a font that has such a weight in the first place. This probably means we'll need:

and specifically to bundle a variable font, like Source Sans 3 VF as seen in the web PR zulip/zulip#24833.

@gnprice
Copy link
Member Author

gnprice commented Apr 14, 2023

Other notes:

  • The upstream tracker has a request for this ability (though expressed as a comment on a different issue): Configured font weights do not align with custom font flutter/flutter#50216 (comment)

    If we confirm that the ability is already there (i.e. that using fontVariations like that does the job), then it'd be good to augment the FontWeight docs with a cross-reference to that, and to follow up on that issue thread 50216.

  • As an alternative, a workaround is suggested here: FontWeight.w200 actually displays w100 flutter/flutter#89960 (comment)

    Namely, one can define a font family that’s just the desired weight, and use that family where desired.

    That shouldn't be necessary for our purpose, though, if using fontVariations works as expected. (It's not clear what was the cause of the now-fixed issue the workaround was suggested for, so it's hard to say if using fontVariations would have successfully worked around that issue too.)

@chrisbobbe
Copy link
Collaborator

[…] specifying an arbitrary weight, as a number, by using design axis wght

[…]

[…] Probably it works fine even if the font isn’t variable, though, as long as you pick a weight the font does have.

Hmm, really? It sounds to me like a non-variable font wouldn't respond to turning a "wght" dial: AIUI, "wght" is an axis that a variable font can optionally declare. Are you thinking Flutter gives us some special "adapter" logic to interpret "wght" for a font that hasn't declared that axis?

In a test just now on iOS, I requested the system font "Menlo" and the text didn't visibly change when I changed "wght", including through the specific values 400 and 600.

In contrast, I tried bundling the variable font SourceCodePro-VariableFont_wght.ttf with the app, and it did respond to changing "wght". In fact I could tell a difference between 200, 250, and 300, which I think confirms that we can set a non-centenary font weight (yay!).

@gnprice
Copy link
Member Author

gnprice commented May 17, 2023

The docs did sound that way:

  • The docs suggest this feature is there for the sake of variable fonts. Probably it works fine even if the font isn’t variable, though, as long as you pick a weight the font does have.

but I'd hoped that was just a matter of emphasizing the use case. Ah well.

In fact I could tell a difference between 200, 250, and 300, which I think confirms that we can set a non-centenary font weight (yay!).

Sounds like the experiment is a success, though, so we can close this issue. Thanks for trying it out!

@gnprice gnprice closed this as completed May 17, 2023
@chrisbobbe
Copy link
Collaborator

I think there might be more worth investigating in this area, but then again it could be a small thing.

When we request a variable font that supports wght, we'll control the weight with fontVariations / 'wght'. But I think we'll also want to set fontWeight, for the sake of glyphs that need to be handled by a fallback font. I'm concerned that setting fontWeight will actually interfere with the glyphs rendered in the desired, variable font. In my experiments, those glyphs sometimes respond to a fontWeight that's set alongside a fontVariations / 'wght'.

…Although I don't yet see that result when the fontWeight value matches the wght value. 🤷‍♂️

Does this seem like a useful area to investigate?

@gnprice
Copy link
Member Author

gnprice commented May 17, 2023

Sure. I guess the question there is just: if you set fontWeight: FontWeight.w200 but fontVariations to have wght of 250, do you get glyphs for

  • weight 250, same as if you'd set only wght
  • or weight 200, same as if you'd set only fontWeight?

Should be a quick add-on to the experiment you already have handy.

@gnprice gnprice reopened this May 17, 2023
@chrisbobbe
Copy link
Collaborator

Hmm. In that experiment, as far as my eye can tell, the glyphs I get are the same as I get if I only set wght. Then as I raise fontWeight, the glyphs stay the same until I cross from FontWeight.w500 to FontWeight.w600. Then, they're thicker, but they stay the same as I keep raising fontWeight.

I see that same "threshold" effect when I set wght to 300.

I see that same "threshold" effect when I set wght to 400.

I see that same "threshold" effect when I set wght to 401, except now the threshold is the cross from FontWeight.w600 to FontWeight.w700.

I also see that new "threshold" effect when I set wght to 500.

When I set wght to 501, the threshold changes again: it's the cross from FontWeight.w700 to FontWeight.w800.

I also see that new "threshold" effect when I set wght to 600.

When I set wght to 601, the threshold changes again: it's the cross from FontWeight.w800 to FontWeight.w900.

I also see that new "threshold" effect when I set wght to 700.

When I set wght to 701 or higher, it doesn't seem to matter if I pass fontWeight, or with which of the FontWeight constants. (They go up to FontWeight.w900.)

@gnprice
Copy link
Member Author

gnprice commented May 17, 2023

Hmm. In that experiment, as far as my eye can tell, the glyphs I get are the same as I get if I only set wght.

IOW the good, hoped-for answer, right?

And then it sounds like wght continues to prevail unless the discrepancy between it and fontWeight is very wide, like 250 vs. 600, or 501 vs. 800.

It seems a bit odd that fontWeight starts having an effect in that case. Possibly there's a bug there. But in practice I think we're always going to want the two to be in alignment — the fontWeight value will be just wght to the nearest 100, or anyway the nearest available value. E.g. if wght is 450, we'll want fontWeight to be w400 or possibly w500.

So it seems like everything looks good for that. Does that sound right to you?

@chrisbobbe
Copy link
Collaborator

IOW the good, hoped-for answer, right?

Yes, that's right. Since I don't understand what's causing the effect, I'm not sure if we'll be safe with a different font that I haven't tested yet 🤷 or if the effect is likely to vary in future Flutter versions, or between Impeller and Skia, iOS and Android, etc.

But at least we have this thread that we can follow up on if something seems wrong in the future.

By the way I think we don't want to set a weight property for a variable font in the pubspec.yaml? Not 100% sure though 🙂 https://docs.flutter.dev/cookbook/design/fonts#2-declare-the-font-in-the-pubspec

@gnprice
Copy link
Member Author

gnprice commented May 17, 2023

Cool. There's always the possibility of new problems, but we can deal with those as they arise. I think we've now done the experiment we wanted to do, so there's no longer something for this issue to track.

By the way I think we don't want to set a weight property for a variable font in the pubspec.yaml?

I agree. That property is supposed to correspond to the weight of what's actually in the font file, so there's no one value that would make sense for it to be set to in the case of a variable font.

@gnprice gnprice closed this as completed May 17, 2023
@chrisbobbe
Copy link
Collaborator

Linking flutter/flutter#33709 just because it has context on support for variable fonts in Flutter.

chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 17, 2023
For background on our interest in variable fonts, see zulip#65.
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 18, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 23, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 25, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 26, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
@gnprice gnprice added the a-content Parsing and rendering Zulip HTML content, notably message contents label May 27, 2023
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this issue May 31, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
gnprice pushed a commit to chrisbobbe/zulip-flutter that referenced this issue May 31, 2023
For background on our interest in variable fonts with a "wght" axis,
see zulip#65.

One thing I noticed when adding such a font ('Source Code Pro', in a
commit coming soon) is that by default, the text was drawn really
lightly; in fact, Flutter seemed to be using the font's lightest
weight by default. I guess I'd assumed Flutter would pick a "normal"
weight by default, as it does for non-variable fonts. Possibly
that's just because Flutter hasn't fully caught up with this recent
development in fonts. But also, I'm not sure if these new fonts all
*have* mappings from "normal", "bold", etc., to values on their
"wght" axes...whether such mappings are standard/predictable, or at
least declared by the font in structured metadata.

Anyway, in my design here, it means that if you want to use one of
these fonts, you still need an incantation (weightVariableTextStyle)
to render text where a normal weight makes sense. Hopefully that's
not too burdensome, but it comes with a benefit: as long as that's
the norm, I think we're unlikely to misuse `fontWeight` to
control glyphs that want to be controlled by "wght".

Much of the complexity in this commit comes from handling glyphs
that need to be rendered in a fallback font that doesn't have a
"wght" axis; see clampVariableFontWeight and how we use that. It
means those glyphs will have approximately the weight of the other
glyphs...not essential, but nice to have.

Some complexity comes from extending Flutter's support for the
"bold-text" accessibility setting, so that it applies to these new
fonts that use "wght". Ideally we wouldn't regress on our support
for that platform setting, but in this design, it means callers have
to have a BuildContext on hand; hmm.
@gnprice gnprice added the a-design Visual and UX design label Jun 14, 2023
@gnprice gnprice moved this to Done in Flutter app Sep 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a-content Parsing and rendering Zulip HTML content, notably message contents a-design Visual and UX design
Projects
Status: Done
Development

No branches or pull requests

2 participants