wght
axis range must include 400
. For example: 100-900
, 400-900
, 100-400
.In addition to complying with the requirements listed in the New additions & Upgrading fonts section:
Name ID 6
should be preserved if possible.fvar
table.ttfautohint-vf
produces bad results, we can release the family unhinted.Font file names must be based on the following schema:
Suffixes like VF
or VAR
or any other must not be appended to the file name. Instead the axes are appended in between brackets:
FamilyName[axis1,axis2].ttf
e.g. Montserrat[wdth,wght].ttf
wght
always last).If your font contains unregistered axes not found in the Microsoft registered axes, they should be capitalized and be listed first (alphabetically).
e.g. Montserrat[GOOF,VEST,wdth,wght].ttf
If the family consists of two VFs, one for Italic, the other for Roman, the fonts should be named:
e.g. Montserrat[axis1,axis2...].ttf
and Montserrat-Italic[axis1,axis2...].ttf
A variable font is simply a static font that has some additional tables FVAR, GVAR etc. These new tables allow text clients to visually alter the font so it has a different appearance to end-users.
Type designers tend to conceive of the variable font as consisting of a bunch of “master fonts” which can then be interpolated between. But in fact, there is only a single master, and what the designer thinks of as additional masters are just sets of instructions to move points around (the famous delta points). That single master is the font origin, or in the OpenType Specification the zero origin.
Often font developers are unaware of what the font origin is within their fonts. They will then complain that Fontbakery is failing many checks. It is recommended that font developers read the Microsoft OpenType Font Variations Overview to better understand how a variable font works.
The important thing to know is that the font origin will be the actual default instance displayed in environments that don’t support the variable font format (and the only accessible instance for some other). For example, if the font origin of the font is the Thin
style, then in some environments, only the Thin
instance will be displayed. GF tends to seek consistency between the name and the displayed font: so the full name of the variable font would be Font Name Thin
. That way, if variable font specific tables are to be removed, the resulting static font would have matching bits and name records.
It often happens that designers are annoyed by that. The only way to work around that is to add a Regular
master and make it the zero origin of the font or to modify directly the name tables. We do not recommend any of those tricks; the first one will increase the file size (if you don’t strictly need a Regular master for your design), and the second one will create an inconsistency between the style displayed by default and the style name.
The Axis Registry is now a Python module and has its own repository. All related issues should be opened there.
Google Fonts supports all the Microsoft registered axes for variable fonts. To follow their convention, MS supported axis tags should be written in lowercase using their convention, and tags of the unsupported ones should be written in capitals.
For example, the Weight axis tag is by convention wght
, and a custom axis that we would call “Jump” could have the following tag: JUMP
.
GF has its own Axis Registry, which defines the names and ranges of additional axes supported by the API. This registry is used to generate the static instances of each variable family (which you can find in the downloadable zip file); the API will generate only those locations registered in the registry.
For example, if your VF has a JUMP[0-100]
axis, which is supposed to fall back to Down[0]
and Up[100]
styles, the API would be able to generate such static instances only if the Axis Registry contains a definition of a “Jump” axis.
To provide a consistent user experience, GF cannot publish fonts with unsupported custom axes. Too great is the chance of a similar axis being accepted later under a different name with live fonts being subject to regressions.
The requirements and principles of axis definition have been established mainly by a cross-functional group of fonts team members by Q3 2022 and have been documented in the Axis Registry Protocol. If you want to see a custom axis of yours added, please refer to the protocol for detailed information on the requirements and process.
You can submit your fonts without the unsupported custom axis simply by stripping it of the axis at the binary font level rather than removing it in the sources, using fonttools’ instancer.
This example removes the CNTR
axis:
fonttools varLib.instancer -o "fonts/variable/Akshar[wght].ttf" CNTR=0 "fonts/variable/Akshar[CNTR,wght].ttf"
Once a new axis has been accepted into GF’s Axis Registry, you may submit an update of your font containing the new axis.
Any new variable font with a weight or width axes will need the instance’s coordinate values to match the conventional usWeightClass and the usWidthClass of the said instances. In order to do so you will probably need to set up an axis mapping (process described below).
wght
name | wght coordinate value |
---|---|
Thin | 100 |
ExtraLight | 200 |
Light | 300 |
Regular | 400 |
Medium | 500 |
SemiBold | 600 |
Bold | 700 |
ExtraBold | 800 |
Black | 900 |
ExtraBlack | 1000 |
wdth
name | wdth coordinate value |
---|---|
UltraCondensed | 50.0 |
ExtraCondensed | 62.5 |
Condensed | 75.0 |
SemiCondensed | 87.5 |
Normal | 100.0 |
SemiExpanded | 112.5 |
Expanded | 125.0 |
ExtraExpanded | 150.0 |
UltraExpanded | 200.0 |
opsz
name | opsz coordinate value |
---|---|
Xpt | X |
between 5 and 1200 |
X can be any integer number value within the minimum (5) and maximum (1,200) as defined in the Google Fonts Axis Registry for the Optical Size axis.
The default value should not be elided in the STAT table (#83).
Named sizes like “Display”, “Text”, “Micro” etc are not allowed, because they are imprecise and inconsistent.
As of May 2023, the download ZIPs available from fonts.google.com will only create just 2-5 sets of static fonts from your optical size range, using values in the axis registry, and a “clamping” heuristic codenamed the “green dot algorithm.” It is helpful for users to have the same named styles available as static fonts in the ZIP also available as named styles in the STAT table.
ital
/ slnt
GF only supports the ital
axis as a boolean (0
/1
) value to link two separate VFs (Roman/Italic) in the STAT table. And slant axis if the font is not meant to have italic instances.
→ GF doesn’t support the ital axis within one VF as a variation axis.
So if you have one VF with slant
or ital
axis, it won’t have italics served by GF API. If you want italic instances served by the GF API, then you will have to deliver two variable font files.
e.g. Texturina[wght].ttf
and Texturina-Italic[wght].ttf
Style linking between these two files will be preserved by:
FontName
for the Roman font, and FontNameItalic
for the Italic font. The Builder will set that up for you using default settings and/or your STAT table values.ital
axis in the STAT
table.As well as the style-linking bits used to link static fonts explained in this section:
head
and OS/2
tablepost
table.A set of axes form a “design space” and you should understand this concept. You can read these articles to get familiar with it:
Be careful to the following because this is confusing for designers who don’t have a broad understanding of web and software engineering.
As a designer, you map your masters and instances to design(space) coordinates that fit your process. This is personal to the design process.
As an example, you could choose stem thicknesses to map your styles on the weight axis:
Style name | Design coordinates |
---|---|
Light | 30 |
Regular | 40 |
Bold | 70 |
The font file though should display values that make sense to users and softwares, these are the user(space) values. A user shouldn’t have to dig into a font binary file to find the location of common styles, so for example, on the weight and the width axis, these values are standardized. They should refer to the usWeightClass (”us” as in “user”) and the usWidthClass of the OS/2 table. Indeed these values are the ones used on the web and in desktop app to select styles. Be also aware that most foundries will rip out the name tables from webfonts to make them unusable on desktop app. The only values remaining to select a style would then be the user values.
See some CSS properties that a developer would use, whatever the actual style name you gave to your instance:
font-style: normal;
→ will select the style at 400
font-weight: bold;
→ will select the style at 700
font-weight: 500
→ a “Medium” weight style is expected.font-variation-settings: 'wght' 300 'wdth' 75
→ Condensed Light instance expected.This is known by developers and software engineers who are supposed to have read the OT Spec (which are rules for machines to support the OpenType font format) to know how to implement font support (or some guidelines summarizing them).
If an axis of the MS Registered Axis doesn’t follow the values and names, then the font is considered as invalid, and a user may not be able to use it on their machine.
To follow our previous example, we then should have these user values:
Style name | User values |
---|---|
Light | 300 |
Regular | 400 |
Bold | 700 |
The Axis Mapping is here to make the conversion between the user values (also called referred as “input”) and design coordinates (also referred as “output”).
For example, if a user enter 400
to get a Regular
style, the font file should return the design at the location 40
. Don’t worry, also developpers finds the input/output logic a bit counter-intuitive.
Style name | User values / input | Design coordinates / output |
---|---|---|
Light | 300 | 30 |
Regular | 400 | 40 |
Bold | 700 | 70 |
This is what it would look like in a .designspace
file:
<axes>
<axis tag="wght" name="Weight" minimum="300" maximum="500" default="400">
<map input="300" output="30"/>
<map input="400" output="40"/>
<map input="700" output="70"/>
</axis>
</axes>
Note that style names are not even mentioned.
For custom axes of your own invention, you can do whatever makes sense to you. Although you are never safe from a new axis being registered, or becoming conventional. You should always make further research to see if there is already some common practices (see GRAD axis).
The axis mapping is set up in Glyphs using the Axis Location
parameter (has to be set in all masters and intermediate instances). Although Google Fonts Tools decided not go with it, to the benefit of the Axis Mapping
parameter that is less redundant and oblige to a consistent approach.
Since version 3.2, GlyphsApp has been using internal coordinates as design values (output), and external coordinates as user values (input). Which is the opposite of how they were handling it before; designer may need to reverse there Axis Mapping when they upgrade.
Now that we have a better understanding of the axis mapping concept, let’s see the three tables linked to the axis mapping that are particularly important to translate correctly the design space: the AVAR
, the STAT
, the FVAR
tables.
AVAR
tableThis table normalizes the progression of the interpolation of one axis on a scale -1:1
, the location of the font-origin being 0
(zero-origin). Basically, it takes the axis mapping and convert it so max location = 1
, default location = 0
, min location = -1
.
The AVAR
has two goals:
To have a better understanding of these two complicated concepts, you can read the articles:
Example: linear interpolation
In the case of a linear interpolation, normalised design and user values on a -1:1
scale are the same. An avar
table in that case is useless and is therefore not exported. Since the interpolation is “linear” all the design space, a simple cross product allows a software to find the location of interpolated instances.
User coordinates | Normalised | Design coordinates | Normalised | |
---|---|---|---|---|
min | 300 | -1 | 30 | -1 |
default | 400 | 0 | 40 | 0 |
interpolated | 500 | 0.3333 | 50 | 0.3333 |
interpolated | 600 | 0.6667 | 60 | 0.6667 |
max | 700 | 1 | 70 | 1 |
A consequence of this interpolation is that you may not be happy with the pace of it. For example the interpolation pace could feel “faster” at the beginning, and “slower” at the end of the axis range. This depends greatly on your design: in general there is a larger optical weight difference between Thin and Medium, than between Medium and Black. Some instance could benefit from not being located “regularly” on the weight axis; maybe Regular could be located closer to light, and Black further away from ExtraBold, like this:
Example: non-linear interpolation
Now let’s pretend that you want your Medium style actually thinner that what the machine could calculate itself, and so you locate it at 45
instead of 50
: you would have then to let the machine knows that it has to adapt the interpolation curve to reach that location. The AVAR table is here to give that factor.
<avar>
<segment axis="wght">
<mapping from="-1.0" to="-1.0"/>
<mapping from="0.0" to="0.0"/>
<mapping from="0.3333" to="0.1667"/>
<mapping from="0.6667" to="0.73334"/>
<mapping from="1.0" to="1.0"/>
</segment>
</avar>
User coordinates | Normalised | Design coordinates | Normalised | |
---|---|---|---|---|
min | 300 | -1 | 30 | -1 |
default | 400 | 0 | 40 | 0 |
interpolated | 500 | 0.3333 | 45 | 0.1667 |
interpolated | 600 | 0.6667 | 62 | 0.73334 |
max | 700 | 1 | 70 | 1 |
All of that is suppose to explain why Google Fonts recommend to set up an AVAR table in variable fonts having a weight axis—although it depends greatly on the design and the axis range.
The hard compromise to make is often to find the right balance between what your instance should look like visually and the pace of the interpolation—indeed both factors can come in contradiction.
GF only allows weight and italic particles for the instances in the fvar
table of a variable font. If a font contains additional axes, they must not be mentioned in the instance names and the coordinates for each instance must be set to reasonable default. For example if your font contains a wdth
axis, you don’t want every instance’s wdth coordinate value to be set to Condensed (75
), you would set it to Normal (100
).
Google Fonts only allows the following named instances:
Roman | Italic |
---|---|
Thin | Thin Italic |
Light | Light Italic |
Regular | Italic |
Medium | Medium Italic |
SemiBold | SemiBold Italic |
Bold | Bold Italic |
ExtraBold | ExtraBold Italic |
Black | Black Italic |
We have imposed this restriction for the following reasons:
When a font uses only custom axes and does not have a wght
axis, you can now define named instances in the fvar
table for at least one of the custom axes used. This allows users to easily access the named instances from the font drop-down menus.
However, please note that these instances will be accessible only in the Variable font and will not be included in the downloaded zip file for the font. Make sure that the named instances have a corresponding definition in the font’s STAT table. Kablammo could work as a example of this case.
All variable fonts must contain a STAT
table (Style Attributes Table). This table has several features but a key benefit is that it will enable desktop applications to have better font menus. Currently, most font menus only offer a single drop down menu to select a font style. A STAT
table enables us to have a drop down menu for each variable font axis.
We recommend reading the MS Spec STAT table info to know more about this table.
Creating good STAT tables is complex. Fortunately, GF has created a gftools
script called gftools gen-stat which can generate a STAT
table for a family automatically based on GF Axis Registry. The Builder is wrapping that script, which means that you can set up the STAT
table directly with this tools.
A STAT
table is defined by these fields:
Axis index / Axis order
GF requires wght
and ital
axes to be last.
Axis name ID
This value will refer to a name ID
in the name
table. The axis name should be full string with first letter in capital, for eg. “Weight”.
Axis tag
Four-letter ID of the axis. In lowercases for MS registered axes, and in capitals for MS unregistered axes (cf. paragraph above). E.g. “wght” and “JUMP”.
<!-- DesignAxisCount=3 -->
<DesignAxisRecord>
<Axis index="0">
<AxisTag value="opsz"/>
<AxisNameID value="257"/> <!-- Optical size -->
<AxisOrdering value="0"/>
</Axis>
<Axis index="1">
<AxisTag value="wght"/>
<AxisNameID value="256"/> <!-- Weight -->
<AxisOrdering value="1"/>
</Axis>
<Axis index="2">
<AxisTag value="ital"/>
<AxisNameID value="278"/> <!-- Italic -->
<AxisOrdering value="2"/>
</Axis>
</DesignAxisRecord>
Axis values
STAT
table format for that Axis Value:
→ GF doesn’t recommend format 2 which allows ranges.
Axis Index that refers to a name ID in the name table
Value that refers to the user value.
Linked value for style linking:
→ 700
for link to Bold on the wght axis, 1
for link to Italic on the ital axis.
Flags
→ if elided/default (2
) or not (0
).
Example for Regular instance in the STAT
table:
<AxisValue index="5" Format="3">
<AxisIndex value="1"/>
<Flags value="2"/> <!-- ElidableAxisValueName -->
<ValueNameID value="261"/> <!-- Regular -->
<Value value="400.0"/>
<LinkedValue value="700.0"/>
</AxisValue>
gftools gen-stat
and the Builder allows you to have external config files which simplify the set up of the STAT table. Read the chapter about how to build a font to have a better understanding of this file.
In 2021, only one desktop application use the STAT table: Microsoft Office for Mac (version 16.46, February 2021 update). However, Indesign, Sketch and other pro type setting applications provide sliders for users to select individual axis locations.
According to the Google Fonts specification, every instance that is allowed to be a part of the fvar
table should also be listed in the STAT table with equivalent values and names. However, the STAT table can also include axis values with string labels which can add extra style variants. This means that fonts with a wght
axis range of 1 to 1000 can have named instances in the STAT table for the 1 (Hairline) and 1000 (ExtraBlack) positions for desktop applications that could make use of this table information.
The above is particularly crucial for variable fonts that only include custom axes. The STAT table with a full set of style variants defined for all the custom axes will provide richer information about the axes of variation and individual styles within the family. You can inspect Sixtyfour as a reference.
The fonts API is a system used by millions of people, with lots of different software, and so the system tries to support them all as best as it can - especially with ‘backwards compatible’ changes that do not “break” existing usage.
As we are in a transition period where some software is VF capable and others are not, or, the old versions of the newly VF capable software remains in use, according to that principle of backwards compatibility, when a variable font is onboarded to Google Fonts, the API provides “fallbacks”, static fonts derived from the variable font, for legacy software. And, according to the systematization principle, the system goes along the axis, and derives a static font at each of the nine 100 values, if the axis covers that value (whether or not they are included in the designer’s original design space), and names it accordingly.
For example, if a font design space includes a wght
axis ranging from 300
to 700
but only includes the Light
Regular
and Bold
instances, the API will also generate the Medium
and SemiBold
static fonts by default.
Those static font files are included in the download ZIP file alongside the VF font file, and they are served as web fonts to web browsers not capable of using VFs.
The manual hinting of variable font is a complicated process and the auto-hinting often results in a worse rendering than no hinting at all. That is why GF recommend to not hint variable fonts in general. If the font is aimed to a particular device or context GF recommends the tool VTT and you can read the guide to hint variable fonts with VTT to learn how to do it.
gftools fix-nonhinting
if you don’t use gftools builder
.gftools fix-hinting
. How to use variable fonts:
Testing web pages dedicated to variable fonts:
You can view the name tables using these tools:
Some font testing web pages allow you to view a selection of tables: