If you are trying to use a variable font in your custom block theme via theme.json
, you may be running into some issues that I also saw and, mostly, solved.
As of Gutenberg 16.1.2 and WordPress 6.2, there are no editor controls for variable font axes—the thing that allows you to control things like weight on a sliding scale instead of as discreet values (400 for normal, 700 for bold, etc.). However, if you’re developing a custom theme, do you really want to have to adjust sliders for every heading and bit of text manually? Instead, I’ve taken a different approach defining separate font families for each style I want to use.
Before we dive into variable font settings, let’s take a brief look at how fonts are defined in theme.json
. If you’ve already got a handle on that, skip down to the solution.
Defining fontFamilies
Adding fonts that are selectable in the editor is as simple as adding a fontFamilies
array to theme.json
:
{
"settings": {
"typography": {
"fontFamilies": [
{
"fontFamily": "'Josefin Sans', sans-serif",
"name": "Title",
"slug": "title"
}
]
}
}
}
Each object in the array defines a selectable font in the editor. The name
is the label that is shown in the editor, and the slug
must be a unique string that gets turned into a CSS custom property (or variable) like --wp--preset--font-family--title
. The fontFamily
is the equivalent of the font-family
CSS property, which means that you should not only add the intended font family name, but also as many fallbacks as you want. Here I’ve just added sans-serif
as the fallback, which will use the default sans-serif font defined by the user’s system. Ideally, you would painstakingly select a curated list of similar-looking fonts that may or may not be available to a user, but perhaps this practice is a holdover from the old days.
Note that this will let you select a font family in the editor called “Title”, but will not necessarily display the font unless you’ve enqueued the font assets yourself elsewhere. I won’t bore you with how we used to load custom font assets, since there’s a better way now.
Using fontFace
Thankfully, since the Web Fonts API was introduced in Gutenberg 12.8 and WordPress 6.0, you don’t need to manually load font assets anymore. The fontFace
property of a fontFamilies
object lets you define just about everything you would if you were writing an @fontFace
CSS declaration, including the path to the font file assets:
{
"settings": {
"typography": {
"fontFamilies": [
{
"fontFamily": "'Josefin Sans', sans-serif",
"name": "Title",
"slug": "title",
"fontFace": [
{
"fontFamily": "Josefin Sans",
"fontStyle": "auto",
"fontWeight": "100 900",
"fontDisplay": "swap",
"src": [
"file:./assets/fonts/josefinsans-subset.woff",
"file:./assets/fonts/josefinsans-subset.woff2"
]
}
]
}
]
}
}
}
The most important (and required) properties that must be defined are fontFamily
and src
. This fontFamily
property is slightly different than the one in the parent object, as this is the singular name that the font will be accessed by, which should correspond to the first item in the parent fontFamily
list.
You can reference MDN for values accepted by fontStyle
and fontWeight
. Generally, if it’s a static (non-variable) font, you’re just letting the browser know what weight and style the font provides. This example happens to use a variable font (slid that right in,did you notice?), so I’m setting a range of 100 900
which is the range the variable font provides.
And finally, the magic: the src
array points to the font files in your theme that you have downloaded from Google Fonts or otherwise procured. I’m using Glyphhanger to subset and format fonts into woff
and woff2
files (you probably only need the latter).
Notice that fontFace
is an array—for a static font, you’ll generally have a few different files, one for each weight & style combo, which you’ll need to add as different objects in the array. If you do, be sure to use the same fontFamily
name so that you’re just adding available styles and weights to one selectable typeface. The need to load a bunch of different files is reduced or sometimes completely unnecessary with variable fonts.
Use the same variable font with different variation settings as separate font families
In order to make use of a variable font like Recursive, which has more than just a weight and slant axis, my solution is to use the same variable font file while defining separately-named font faces. This gives us font options in the editor to use a cursive style and monospace style, which are custom axes that Recursive provides.
This is accomplished with the fontVariationSettings
property, which is how we can set all of the different axis values on a variable font:
{
"settings": {
"typography": {
"fontFamilies": [
{
"fontFace": [
{
"fontDisplay": "swap",
"fontFamily": "Recursive",
"fontStyle": "auto",
"fontVariationSettings": "'MONO' 0, 'CRSV' 0, 'CASL' 0, 'slnt' 0",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
},
{
"fontDisplay": "swap",
"fontFamily": "Recursive",
"fontStyle": "italic",
"fontVariationSettings": "'MONO' 0, 'CRSV' 0, 'CASL' 0, 'slnt' -14",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
}
],
"fontFamily": "Recursive, sans-serif",
"name": "Sans-serif",
"slug": "sans-serif"
},
{
"fontFace": [
{
"fontDisplay": "swap",
"fontFamily": "Recursive Cursive",
"fontStyle": "auto",
"fontVariationSettings": "'MONO' 0, 'CRSV' 1, 'CASL' 1, 'slnt' 0",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
},
{
"fontDisplay": "swap",
"fontFamily": "Recursive Cursive",
"fontStyle": "italic",
"fontVariationSettings": "'MONO' 0, 'CRSV' 1, 'CASL' 1, 'slnt' -14",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
}
],
"fontFamily": "'Recursive Cursive', cursive",
"name": "Cursive",
"slug": "cursive"
},
{
"fontFace": [
{
"fontDisplay": "swap",
"fontFamily": "Recursive Monospace",
"fontStyle": "auto",
"fontVariationSettings": "'MONO' 1, 'CRSV' 0, 'CASL' 0, 'slnt' 0",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
},
{
"fontDisplay": "swap",
"fontFamily": "Recursive Monospace",
"fontStyle": "italic",
"fontVariationSettings": "'MONO' 1, 'CRSV' 0, 'CASL' 0, 'slnt' -14",
"fontWeight": "300 900",
"src": [
"file:./assets/fonts/recursive-subset.woff",
"file:./assets/fonts/recursive-subset.woff2"
]
}
],
"fontFamily": "'Recursive Monospace', monospace",
"name": "Monospace",
"slug": "monospace"
}
]
}
}
}
Expand the code block above to see more, but the gist is that for each style of font I want to be selectable in the editor, I’ve defined a font face with a unique name for each that uses the same font files. For this font in particular, I had to define separate font faces for the normal (auto) and italic styles, which just sets a different value for the slnt
axis in fontVariationSettings
.
Now I can choose any of these styles as different fonts in the typography area in the editor (you may need to open the kebab menu to get the font family options):
At the time of posting, this is exactly what I’m using in this theme. If you wanted, you could use a single variable font with different styles defined like this to use for headings, body text, etc. And you can set the default font family for all headings, for instance, like this:
{
"styles": {
"elements": {
"heading": {
"typography": {
"fontFamily": "var(--wp--preset--font-family--cursive)",
"fontStyle": "normal",
"fontWeight": "600"
}
}
}
}
}
I’m still using CSS to handle some things, like links. While you can set the font family of links similar to headings via theme.json
, I wanted to use the variable font for something that static fonts can’t do: animate.
a:where(:not(.wp-element-button)) {
font-variation-settings: "MONO" 0, "CRSV" 1, "CASL" 1, "slnt" 0;
transition: font-variation-settings var(--wp--custom--transitions--default)
ease-in-out;
@media prefers-reduced-motion {
transition: none;
}
&:hover,
&:focus {
font-variation-settings: "MONO" 0, "CRSV" 1, "CASL" 1, "slnt" -14;
}
}
Variable fonts in the Editor
Update 2023-08-08:
As of Gutenberg 16.3.0, my variable fonts are showing up correctly in the editor! 🎉 No further tweaks are necessary to make them work.
Original post 2023-07-20:
Unfortunately, as of Gutenberg 16.1.2 and WordPress 6.2, my fonts don’t quite display properly in the editor. Maybe it’s just this specific font, but the sans-serif style is for some reason acting as if it’s both monospace and not, and also casual when it shouldn’t be.
Here’s a screenshot of what the previous paragraph and heading looks like in the editor:
It’s frankly a little hard to look at, but I’ll update this post if I figure out a workaround or if some new version of Gutenberg somehow fixes the situation.
Are you using variable fonts in custom block themes? Have you run into the same issues or found other solutions? Let me know!
Broadcast a message