Flutter. The complete typography with a single font

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
Subscribe to my newsletter
Read articles from Yuriy Novikov directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
