Skip to main
Article
Miriam gesturing as she talks in a video thumbnail

Visualizing Responsive Typography

What do all the numbers in our clamp() do?

There are multiple tools that can help create a fluid font-size calculation for CSS – generally expressed as a clamp() function combining em (or rem) with vw (or vi) units. But the results are difficult to understand at a glance, so I wanted to visualize what’s going on, and how the various units interact.

This post is part of a series on revisiting fluid typography:
  1. Relative Units & TypographyWith special guest Alan Stearns
  2. Reimagining Fluid TypographyAre we responding to the right inputs?
  3. Revisiting Fluid TypeWith special guest Richard Rutter
  4. Designing for User Font-size and ZoomUsing modern CSS units and math functions
  5. Visualizing Responsive Typography

The simplest interaction between font-size and viewport width would be a 1-to-1 relationship – keeping the values equal at all times. We can express that in CSS as a font-size of 100vw.

html { font-size: 100vw; }

That’s very direct and simple, but a terrible idea. When the viewport width is 0px, the font-size is also 0px. If the viewport grows to be 3250px, the font-size will also be 3250px. The viewport can’t go below 0px, but (in theory) there’s no upper limit here.

Tools like Utopia.fyi will give you a more complex output with several parts:

:root {
  --step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
}

I built a Codepen visualization to see how things change as I adjust the different values:

We could start by setting a more leisurely rate of change – adjusting the slope (or rate) of growth. To do that, we need to adjust the vw value. At 50vw we would get a font that scales at half the rate of the viewport, but even that seems too dramatic. The default scale from Utopia.fyi uses 0.2273vw for the primary font size. That’s a 1px font-size change for every 440px of viewport resizing! Even the largest font in that scale uses less than a 2vw response rate. Let’s round it off for the sake of our demo:

html { font-size: 0.25vw; }

Now we’re growing at a more reasonable rate, but now our font is way too small. It still starts at 0px for a 0px viewport – and would only be 1px tall on a 400px screen. At that rate, we won’t get to a standard 16px font size until the browser hits 6400px – a very wide screen. This subtle slope only makes sense if we start with an offset. We can do that by adding two values together:

html { font-size: calc(17px + 0.25vw); }

That offset value moves our slope up and down in the visualization, without impacting the slope that we set earlier. Now a 400px browser will give us 18px font-size, and a 1200px browser will result in a 20px font. That’s much more appropriate!

But we still have infinite scaling, and we don’t really need that. We could improve our algorithm even more by providing boundaries with a clamp() function:

html { font-size: clamp(18px, 17px + 0.25vw, 20px); }

That establishes a fixed range for our font-size change, which we can think about in two ways. On the surface we can see the font-size range from 18px to 20px. But when we combine that with the slope and offset, we also have a range of viewport sizes where the font is in transition between those two sizes. In this case, the font begins to grow once the viewport is larger than 400px, and stops growing when we reach 1200px.

As a tool, Utopia starts from these four inputs – min font-size, min viewport, max font-size, and max viewport – and works backwards to determine the proper offset and slope.

I think this is a useful pattern. I like somewhat smaller fonts in tight spaces, and larger fonts when there’s more room. But that comes with caveats – and it’s important for users to get final say with the ability to zoom in or out. If we’re not careful, viewport units and clamp functions can make fonts unable to zoom. I show a few examples of that in my video above, and there are more situations to watch out for, but a simple rule you can follow:

If the maximum font size is less than or equal to 2.5 times the minimum font size, then the text will always pass WCAG SC 1.4.4, at least on all modern browsers.

Utopia helpfully provides a warning when we create scales that are inaccessible. Maybe I can add that to my demo as well. In the meantime, play with that ‘page zoom’ slider to test different values and see how they interact.

Posts about Typography

  1. Close-up of keys on an old Spanish typewriter, part of the space bar, a, s, d, z, x, and MAYÚSCULAS (capslock) with release above it
    Article post type

    Designing for User Font-size and Zoom

    Using modern CSS units and math functions

    When I tried setting my browser font-size preferences, I found it broke more sites than it improved, and I quickly moved back to the default. So what went wrong, and how can we fix it?

    see all Article posts
  2. Winging It post type

    Revisiting Fluid Type

    With special guest Richard Rutter

    Miriam’s been asking questions about fluid typography, and how a website design should plan for (and respond to) user preferences. And we’re not the only ones thinking about it! This month we continue the conversation with Richard Rutter from Clearleft, the experts behind excellent resources like Utopia.fyi and WebTypography.net.

    see all Winging It posts
  3. A case of letterpress type with arrows pointing outward and a cursor hand overlaid
    Article post type

    Reimagining Fluid Typography

    Are we responding to the right inputs?

    For many years, it has been ‘best practice’ to use relative units (especially em and rem) for sizing text. That’s great! But after playing around with my user preferences, I think we can improve on the common approaches.

    see all Article posts