Flutter. The complete typography with a single font

Yuriy NovikovYuriy Novikov
5 min read

Originally posted on Medium

1. Font variations

Flutter’s TextStyle class has a fontVariations property that takes a List<FontVariation> as an argument.

Here is an example:

           Text(
              'Brown fox jumps over the dog',
              style: TextStyle(
                  fontFamily: 'RobotoFlex',
                  fontSize: 20,
                  fontVariations: [FontVariation.weight(900),],
              ),
            ),

For above to work, RobotoFlex should be a variable font.

2. Variable fonts

Some modern fonts are variable fonts. Variable font can be changed dynamically. It contains some (sometimes many) variations in a single font file.

Google Fonts collection contains a lot of variable fonts.

3. Roboto Flex

Roboto Flex is the most variable font from all Google’s variable fonts. It has 13 variables (lucky number).

Each variable consists of the axis and a list of values.

Combining those variables, we can create an infinite number of different fonts from a single font file.

3.1. Add font to project

We should download the font and unzip the archive. We will see the following files:

The last one is our desired font. It has a very long name that contains all the variable names. It is about 1.5 MB while a regular font is about 100 KB. Makes sense.

We should rename it and add to the project:

and pubspec.yaml:

According to my experiments, the Flutter’s google_fonts package doesn’t work with font variations. Probably, it downloads the static variant of the font instead of the variable font.

3.2. Test variables

Google Fonts site provides a Type tester page where all variables can be tested to see what they should do.

BTW, unmodified Roboto Flex looks exactly like the famous Roboto (the default font on Android devices).

To find a 4-letter variable tag, we should click the info button:

3.3. Examples

I will not go through all variables, you can do it on the above page. I would rather try to create something interesting by combining several variables.

3.3.1. Imitating San Francisco (SF Pro) font

            Text(
              'Brown fox jumps over the dog',
              style: TextStyle(
                fontSize: 44,
                fontFamily: 'SfPro',
              ),
            ),
            Text('Brown fox jumps over the dog',
                style: TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 44,
                    letterSpacing: -0.5,
                    fontVariations: [
                      FontVariation('wdth', 85),
                    ])
           )

The first text uses the SF Pro font — the default font on Apple devices. The second one is Roboto Flex with reduced letterSpacing and width increased using FontVariation.

They are not absolutely identical, a careful typographer will find his 12 differences, but they are similar enough for me (and my users).

3.3.2. Imitating Roboto Condensed

            Text('Brown fox jumps over the dog',
                style: TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 44,
                    letterSpacing: -1,
                    fontVariations: [
                      FontVariation('wdth', 25),
                    ])
           )

We can easily create a Condensed font by just tweaking letterSpacing and giving a smaller value to wdth FontVariation. We can condense it ever more using XTRA variation aka Counter Width.

            Text('Brown fox jumps over the dog',
                style: TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 44,
                    letterSpacing: -2,
                    fontVariations: [
                      FontVariation('wdth', 25),
                      FontVariation('XTRA', 369),
                    ])
           )

3.3.3. Imitating Courier New (monospace)

           Text(
              'Brown fox jumps over the dog',
              style: TextStyle(
                fontSize: 34,
                fontFamily: 'Courier New',
              ),
            ),
            Text('Brown fox jumps over the dog',
                style: TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 34,
                    letterSpacing: 1.5,
                    wordSpacing: 15,
                    fontVariations: [
                      FontVariation('wdth', 120),
                      FontVariation('wght', 100),
                      FontVariation('YTLC', 446),
                      FontVariation('YTUC', 586),
                      FontVariation('YTAS', 550),
                    ])
           )

Obviously, we cannot make a true monospace font from one that is not.

3.3.4. Imitating Impact font:

            Text(
              'Brown fox jumps over the dog',
              style: TextStyle(
                fontSize: 34,
                fontFamily: 'Impact',
              ),
            ),
            Text('Brown fox jumps over the dog',
                style: TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 34,
                    letterSpacing: -0.5,
                    wordSpacing: -2,
                    fontVariations: [
                      FontVariation('wdth', 25),
                      FontVariation('wght', 900),
                      FontVariation('YTLC', 746),
                      FontVariation('YTUC', 986),
                      FontVariation('YTAS', 550),
                      FontVariation('YTFI', 900),
                      FontVariation('GRAD', 150),
                    ])
           )

4. Preconstructing TextStyles

The TextStyle with a lot of variations, can become too long and valuable. It makes sense to preconstruct it for cleaner UI code and better reusability.


final class MyTextStyle {
   MyTextStyle._();

    static final courierNew = TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 34,
                    letterSpacing: 1.5,
                    wordSpacing: 15,
                    fontVariations: [
                      FontVariation('wdth', 120),
                      FontVariation('wght', 100),
                      FontVariation('YTLC', 446),
                      FontVariation('YTUC', 586),
                      FontVariation('YTUC', 586),
                      FontVariation('YTAS', 550),
                    ]);

    static final impact =  TextStyle(
                    fontFamily: 'RobotoFlex',
                    fontSize: 34,
                    letterSpacing: -0.5,
                    wordSpacing: -2,
                    fontVariations: [
                      FontVariation('wdth', 25),
                      FontVariation('wght', 900),
                      FontVariation('YTLC', 746),
                      FontVariation('YTUC', 986),
                      FontVariation('YTAS', 550),
                      FontVariation('YTFI', 900),
                      FontVariation('GRAD', 150),
                    ]);                
}

And then use them like this:

           Text(
              'Brown fox jumps over the dog',
              style: TextStyle(
                fontSize: 34,
                fontFamily: 'Impact',
              ),
            ),
            Text('Brown fox jumps over the dog',
                style: MyTextStyle.impact
           )

The approach even brings performance gains since each TextStyle is constructed only once when it is used for the first time. (Flutter’s static and global variables are lazy loaded.)

5. FontVariation constructors

The FontVariation class has several named constructors. The usage is not required, they exist solely for convenience.

FontVariation.italic(0.9) is the same as FontVariation('ital', 0.9)
FontVariation.opticalSize(1) is the same as FontVariation('opsz', 1)
FontVariation.slant(90) is the same as FontVariation('slnt', 90)
FontVariation.weight(90) is the same as FontVariation('wght', 90)
FontVariation.width(870) is the same as FontVariation('wdth', 870)

6. Final thoughts

Variable fonts like GetX 😀😀 — they give power and flexibility. So, similarly to GetX, they should be used carefully. It is very easy to compromise readability in favor of creativity.

Thank you for reading and happy designing!

Related articles: Flutter. TextStyle cheat sheetFlutter. Fonts

0
Subscribe to my newsletter

Read articles from Yuriy Novikov directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yuriy Novikov
Yuriy Novikov