I’m a big fan of the CSS clamp() function and how it allows for behavior previously only possible with media queries.

The clamp() function takes three parameters: a minimum value, a preferred value, and a maximum allowed value — resulting in a value between each of those.

And while clamp() may be used in a bunch of ways, my favorite use is certainly for fluid typography.

Fluid typography is type that adapts in size based on a viewport width; the smaller the window/device, the smaller the font-size. And as you can imagine, a fluid type system based on the clamp() function that “just works” is pretty cool — but I have something better… let’s scale this.

Scaling type

A typographic scale is a harmonious progression of font sizes, designed to bring balance to type. It can be a little confusing relating fluidity and scale, but to summarize — fluidity is the responsive sizing of type, whereas scale is the way type increases in sized relationally.

Visualize and create type scales with the Type Scale tool.

Now to build a type scale, a value — i.e. 1.250 — is multiplied to a base font size, which generates the next size up, like this:

body {
    --wp--custom--typography--scale: 1.250;
    --wp--custom--typography--normal: 1rem;
    --wp--custom--typography--large: var(--wp--custom--typography--normal) * var(--wp--custom--typography--scale);
    --wp--custom--typography--extra-large: var(--wp--custom--typography--large) * var(--wp--custom--typography--scale);
    --wp--custom--typography--huge: var(--wp--custom--typography--extra-large) * var(--wp--custom--typography--scale);
    --wp--custom--typography--gigantic: var(--wp--custom--typography--huge) * var(--wp--custom--typography--scale);
}

One bit to note is that I am using values relative to my suggested standardized font size slugs for a block theme’s typography. This way themes can be switched with less risk of busted type throughout the site.

This is great for scaling type, but creating a scaled and fluid type system takes a bit more creativity, especially in the context of block themes, but I’ve figured out a method that I’m using — even here on this blog.

Building a type scale with theme.json

If you’re unfamiliar with theme.json, it’s a relatively new mechanism used to configure the editor and provide styles for a site. In short, it’s what makes block themes special.

Now to create a fluid type scale for block themes, we will first need create a CSS custom property for a type scale, within a theme’s theme.json file:

{
    "settings": {
        "custom": {
            "typography": {
                "scale": 1.250
            }
        }
    }
}

Next, we’ll abstract the font-size values from the settings.typography.fontSizes object within theme.json — basically the JSON for what I’ve done to output the earlier snippet I shared.

{
    "settings": {
        "custom": {
            "typography": {
                "scale": 1.250,
                "normal": "1rem",
                "tiny":   "calc(var(--wp--custom--typography--small) / var(--wp--custom--typography--scale))",
                "small":   "calc(var(--wp--custom--typography--normal) / var(--wp--custom--typography--scale))",
                "large":   "calc(var(--wp--custom--typography--normal) * var(--wp--custom--typography--scale))",
                "extra-large":   "calc(var(--wp--custom--typography--large) * var(--wp--custom--typography--scale))",
                "huge":  "calc(var(--wp--custom--typography--extra-large) * var(--wp--custom--typography--scale))",
                "gigantic": "calc(var(--wp--custom--typography--huge) * var(--wp--custom--typography--scale))"
            }
        }
    }
}

And here’s how the scale value, and each font size, is transformed into CSS custom properties, to be used within the editor and on the front-end:

body {
    --wp--custom--typography--scale: 1.250;
    --wp--custom--typography--normal: 1rem;
    --wp--custom--typography--tiny: var(--wp--custom--typography--small) / var(--wp--custom--typography--scale);
    --wp--custom--typography--small: var(--wp--custom--typography--normal) / var(--wp--custom--typography--scale);
    --wp--custom--typography--large: var(--wp--custom--typography--normal) * var(--wp--custom--typography--scale);
    --wp--custom--typography--extra-large: var(--wp--custom--typography--large) * var(--wp--custom--typography--scale);
    --wp--custom--typography--huge: var(--wp--custom--typography--extra-large) * var(--wp--custom--typography--scale);
    --wp--custom--typography--gigantic: var(--wp--custom--typography--huge) * var(--wp--custom--typography--scale);
}

As of now, we have the calculated type scale interpreted as CSS custom properties for each font size.

We could plug this into the settings.typography.fontSizes theme.json object for each size — but that wouldn’t give us the fluidity we’re looking for, just the scale.

Using clamp for fluid type in theme.json

Here’s where the magic happens. Where this all comes together to build fluidity and scale into one type system for block themes.

Within the settings.typography.fontSizes theme.json object, we can set font sizes for the theme. Each font size consists of a name, size and slug. Name is the visual label for which is displayed for a font size, size is the value, and slug is how the value is mapped from JSON to CSS.

The interesting bit here is that size can receive not only standard font size styles and units, but also the clamp() function.

That means we can take our generated scaled sizes and input those into a clamp() function for each font size, setting the minimum, preferred, and maximum values for each, like this:

{
    "settings": {
        "typography": {
	    "fontSizes": [
		{
		    "name": "Large",
		    "size": "clamp(var(--wp--custom--typography--normal), calc(1rem + var(--wp--custom--typography--large--preferred, 3vw)), var(--wp--custom--typography--large))",
		    "slug": "large"
		},
		{
		    "name": "Extra Large",
		    "size": "clamp(var(--wp--custom--typography--large), calc(1rem + var(--wp--custom--typography--extra-large--preferred, 4vw)), var(--wp--custom--typography--extra-large))",
		    "slug": "extra-large"
		}
	    ]
	}
    }
}

I only wrote out the relationship between the large and extra-large sizes, to not toss too much JSON in front of you at once — but the idea persists across each size.

For the clamp() minimum value, I’m using the scaled value one level lower than the current size, and for the clamp() maximum value, I am using the proper scaled value for this size.

For example, you look at the extra-large entry, you’ll see I’m referring to the var(--wp--custom--typography--large) value as it’s smallest font size, and var(--wp--custom--typography--extra-large) as it’s largest.

Now there’s bit that we could also consider scaling perhaps, and the preferred font size — the middle value within the clamp() function. I’ve set them up to receive a CSS custom property as well, but fall back to a +1 vw scale. (A vw unit is relative to 1% of the width of the viewport; great for fluidity.)

I’ve found that stepping the value up one vw works well enough, but you could apply the same scaling abstraction from the minimum and maximum font size values to the preferred value as well.

Thoughts? Ideas?

I’ve explored this method a good bit on my blog here and I quite like it. I’d appreciate if you’d share any thoughts or ideas to improve upon this method.

The best way to get in touch with me is via Twitter at @richard_tabor. Enjoy!

,