website icon indicating copy to clipboard operation
website copied to clipboard

Custom fonts CookBook example not working as expected

Open miquelbeltran opened this issue 5 years ago • 6 comments

I added custom fonts to my project following the explanation in https://flutter.dev/docs/cookbook/design/fonts

In the example you can find:

- family: RobotoMono
      fonts:
        - asset: fonts/RobotoMono-Regular.ttf
        - asset: fonts/RobotoMono-Bold.ttf
          weight: 700

So I followed it and in my pubspec.yaml I have:

fonts:
    - family: Edmondsans
      fonts:
        - asset: fonts/Edmondsans-Regular.otf
        - asset: fonts/Edmondsans-Medium.otf
          weight: 500
        - asset: fonts/Edmondsans-Bold.otf
          weight: 700

Then in my code:

TextStyle(
      fontFamily: "Edmondsans",
      fontWeight: FontWeight.w500,
    );

However I noticed that:

  • The w500 (medium) was not being rendered, and instead, it was rendering the Edmondsans-Regular.
  • The w700 (bold) was not rendering Edmondsans-Bold but instead making a bold version of Edmondsans-Regular (they looked different)

To actually use my Medium and Bold custom font files, I had to use them in a different way:

fonts:
    - family: Edmondsans
      fonts:
        - asset: fonts/Edmondsans-Regular.otf
    - family: Edmondsans-Medium
      fonts:
        - asset: fonts/Edmondsans-Medium.otf
    - family: Edmondsans-Bold
      fonts:
        - asset: fonts/Edmondsans-Bold.otf

Then in my code, this will work as expected:

TextStyle(
      fontFamily: "Edmondsans-Medium",
    );

My configuration info:

[✓] Flutter (Channel beta, v1.7.8+hotfix.3, on Mac OS X 10.14.5 18F132, locale en-DE)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 10.3)
[✓] iOS tools - develop for iOS devices
[✓] Android Studio (version 3.4)
[✓] IntelliJ IDEA Ultimate Edition (version 2019.1.3)
[✓] IntelliJ IDEA Community Edition (version 2019.1.3)
[✓] Connected device (1 available)

This issue here seem to be related: https://github.com/flutter/flutter/issues/29806

I'd suggest to change the cookbook examples until custom fonts work as expected.

miquelbeltran avatar Jul 23 '19 06:07 miquelbeltran

The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the pubspec.yaml manifest. (We should remove the style descriptors in pubspec.yaml now that they are obsolete).

The Edmondsans regular, medium, and bold fonts contain metadata declaring their weights as 400, 410, and 420 respectively. However, the Flutter text subsystem only supports font weight buckets representing even multiples of 100 (https://api.flutter.dev/flutter/dart-ui/FontWeight-class.html). So all three of these fonts are mapped to FontWeight.w400, and the font style matcher can not choose between these fonts based on weight.

Declaring these fonts as different families in pubspec.yaml will work around this.

jason-simmons avatar Aug 15 '19 21:08 jason-simmons

Thanks a lot for the explanation @jason-simmons!

It didn't occur me that my font could have been the one causing this.

I think it would still be good to update the cookbook documentation so it won't confuse other developers.

miquelbeltran avatar Aug 16 '19 09:08 miquelbeltran

Moving to the website for the cookbook.

kf6gpe avatar Jan 27 '20 17:01 kf6gpe

The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the pubspec.yaml manifest. (We should remove the style descriptors in pubspec.yaml now that they are obsolete).

Should we update the docs here to explain that these descriptors are actually ignored?

orestesgaolin avatar Feb 12 '20 10:02 orestesgaolin

The Flutter engine matches fonts within a family based on the metadata in the font itself, not the style descriptors declared in the pubspec.yaml manifest. (We should remove the style descriptors in pubspec.yaml now that they are obsolete).

This looks like a bug in the flutter engine to me. The font file can, as mentioned, have values between two multiple of 100 (e.g. 425).

The value specified in the pubspec.yaml should therefore allow us to override that internal value to something we can actually use.

Working with multiple font families as a workaround would work but is far from elegant in my eyes.

c15yi avatar Apr 21 '22 14:04 c15yi

Based on what @jason-simmons mentioned, I created the following python script to "fix" your custom font files to use the correct weights that flutter respects. Create a src directory and put all your fonts in there. Create an empty out directory and the script will place the new fonts there.

import os
from fontTools import ttLib

# Declare your font file names and the correct weights here
to_change = {
    'Neue Radial B Thin Italic.ttf': 100,
    'Neue Radial B Thin.ttf': 100,
    'Neue Radial B Extra Bold Italic.ttf': 800,
    'Neue Radial B Bold.ttf': 700,
    'Neue Radial B Book.ttf': 500,
    'Neue Radial B Regular Italic.ttf': 400,
    'Neue Radial B Light.ttf': 300,
    'Neue Radial B Book Italic.ttf': 500,
    'Neue Radial B Regular.ttf': 400,
    'Neue Radial B Extra Bold.ttf': 800,
    'Neue Radial B Extra Light.ttf': 200,
    'Neue Radial B Light Italic.ttf': 300,
    'Neue Radial B Extra Light Italic.ttf': 200,
    'Neue Radial B Bold Italic.ttf': 700,
    'Neue Radial B Medium.ttf': 600,
    'Neue Radial B Black.ttf': 900,
    'Neue Radial B Black Italic.ttf': 900,
    'Neue Radial B Medium Italic.ttf': 600,
}

for file, weight in to_change.items():
    with ttLib.TTFont(os.path.join('src', file)) as tt:
        tt['OS/2'].usWeightClass = weight
        tt.save(os.path.join('out',file))

This is probably the best workaround out there at the moment. No multiple font families, and no needing to modify each font individually.

GregoryConrad avatar Jul 17 '22 19:07 GregoryConrad

@jason-simmons : Is this font issue still occurring? If so, I can document this workaround. If not, I'll close this issue.

atsansone avatar May 18 '23 16:05 atsansone

@miquelbeltran, ah the ultimate irony! You filed it, you fix it! :D

sfshaza2 avatar Jul 13 '23 18:07 sfshaza2

Without additional information we're not able to resolve this issue, so it will be closed at this time. You're still free to add more info and respond to any questions above, though. We'll reopen the case if you do. Thanks for your contribution!

github-actions[bot] avatar Aug 02 '23 06:08 github-actions[bot]

I'll work on this now

miquelbeltran avatar Aug 02 '23 08:08 miquelbeltran

Is this font issue still occurring? If so, I can document this workaround. If not, I'll close this issue.

For what I can see, Flutter still only supports multiples of 100 when it comes to the font weight.

Reviewing the cookbook recipe, I see that now it says:

Note that defining the weight property does not override the actual weight of the font. You would not be able to access RobotoMono-Bold with FontWeight.w100, even if its weight was set to 100.

I am thinking, I could add an explanation and workaround in the recipe, e.g.

This can be an issue if the original font file doesn't define its weight as Flutter expects it.

You can workaround this limitation by defining individual font families for each different weight as shown below:

fonts:
 - family: Edmondsans
   fonts:
   - asset: fonts/Edmondsans-Regular.otf
 - family: Edmondsans-Bold
   fonts:
     - asset: fonts/Edmondsans-Bold.otf

And then using them directly in your code:

TextStyle(
  fontFamily: "Edmondsans-Bold",
);

Any thoughts on this? My only concern is that it could be promoting the wrong code practices, so we need to be clear that it is just a workaround for font files that aren't compliant with what Flutter expects.

miquelbeltran avatar Aug 02 '23 10:08 miquelbeltran

@miquelbeltran : That works. These docs are fluid, so we can always change again later if this appears to be in error.

atsansone avatar Sep 01 '23 14:09 atsansone