How-to / Development — 6 minute read

Responsive Typography: Scaling your text with Viewport Units

Written by Oliver Stanley
Jun 11, 2024

Ever landed on a website boasting large, sexy typography. Envious of how it always stays just as bold and expressive regardless of the size of your browser’s window? Say hello to responsive typography. Browser window gets bigger? So does your text. Window gets smaller? You guessed it, the text shrinks too.

No more faffing around with multiple CSS media queries just for your text. Goodbye unexpected widows and orphans as your text wraps. Designers and developers will love it, a win all around.

Using basic HTML and CSS, we’re going to walk through how to implement this technique on your own site.

The steps included in this tutorial are:

  • Understanding ‘vw’s and how they’re relevant
  • Determine our base font size
  • Creating a range of CSS variables that can be applied to style attributes
  • Using these variables in your own CSS classes

The golden ingredient - ‘vw’s

Before we go any further it’s important we get familiar with what a ‘vw’ unit is. This powerful little unit will drive everything we do in this tutorial.

‘vw’ is a unit of measure that can be used in place of ‘px’ values when declaring styles in our site’s CSS. Standing for ‘viewport width’, it gives us a value based on the current width of the user’s browser window. The number you declare refers to a percentage of the window’s width.

E.g. for a browser that is 1920px wide, 50vw would return 960px (50% of 1920px = 960px). Simple. ‘vw’s are what will allow us to scale our text.

Note: Although ‘vw’ is supported across most major browsers, it’s worth checking that it’s compatible with the browsers you are intending to use. You can use Can I use here to help with this.

Determine our base font size

Cited by the folk at Google and founder of Tailwind alike, you may have come across the term ‘rhythm’ whilst you’ve been designing digital interfaces. Rhythm often refers to the increments between the font sizes and margin/padding used throughout a website.

It’s commonplace to see designs use multiples of 4 or 8 when calculating the rate at which their rhythm should grow. In our use case, body copy often starts at 16px, with heading working up like the following: 24px, 40px, 64px and so on.

Why do we care about this?

Well first of all, we need to know what size we intend on using for our body copy and use this as the base for all of our calculations. In this example, I will stick to the tired and tested 16px, but feel free to experiment. We’ll then create responsive values for 24px, 40px and 64px, as determined by our design’s rhythm.

Creating our responsive variables

In addition to our base font, we also need to know the screen breakpoint we want to ‘anchor’ our values around. If users of your website commonly view it on 1920px x 1080px displays, it might be a good idea to use 1920px as your ‘anchor’. Likewise, if your design team has created the site on a 1600px canvas you might decide to use this.

This will be the resolution that all font sizes return their true value. For example, a 16px copy in a browser window that is 1920px wide will be 16px. Make the window larger, the text will grow, anything smaller, the text will shrink.

Here’s a first look at what our CSS variable will look like

—responsive-16: calc((16 / 16 * (100vw / 1920px)) * 16);

What this is actually doing

The size we’re after / base font size x (current window width / breakpoint to anchor around) x base font size for unit conversion

The left half of the equation works out how big the growth factor is in relation to our base size, very similar to how ‘em’ units work. Meanwhile, the right half works out the difference between the current window width and the width we wanted to anchor around. The resulting number is then multiplied by our base font size to ensure we also have a responsive value.

In a 1920px window

(16 / 16) * (1920px (100vw) / 1920px) * 16px, which in turn returns 16px.

Let’s increase the window width to 2560px

(16 / 16) * (2560px (100vw) / 1920px) * 16px, returns 21.333333px.

Let’s decrease the window width to 1280px

(16 / 16) * (1280px (100vw) / 1920px) * 16px, returns 10.666666px (this is tiny, I touch on this in my wrap up below).

Let’s create a set of these variables in the ’:root’ selector of our stylesheet

:root {
—responsive-16: calc((16 / 16 * (100vw / 1920px)) * 16);
—responsive-24: calc((24 / 16 * (100vw / 1920px)) * 16);
—responsive-40: calc((40 / 16 * (100vw / 1920px)) * 16);
—responsive-64: calc((64 / 16 * (100vw / 1920px)) * 16);
}

Applying our CSS variables

Now we’re on the home stretch. We have a set of responsible variables that we can apply to the classes responsible for our typography. You’re usage may vary depending on how you like to build your sites. I have opted to create utility classes, inspired by tailwind, that can be applied to any element in our HTML. Alternatively, you could apply them directly to your p, H1, H2 tags if you’d like to take a more prescriptive approach.

// CSS styles
.text-18 {
font-size: var(—responsive-16);
}
.text-24 {
font-size: var(—responsive-24);
}
.text-40 {
font-size: var(—responsive-40);
}
.text-64 {
font-size: var(—responsive-64);
}

// HTML
<h1 class=“text-64”>Title</h1>
<p class=“text-18”>Some generic copy to go here</p>

If you have not noticed by now, our newly created responsive units can be applied to more than just font sizing. We can use the same variables and create utility classes for margin and padding.

.p-16 {
padding: var(—responsive-16)
}
.p-24 {
padding: var(—responsive-24)
}

Wrap up

A word of warning. Be wary that with great power comes great responsibility (insert Spider-man meme). Unfortunately, window height doesn’t always grow proportionally with window width. At larger breakpoints you might want to use media queries to make adjustments and bump up the size of your base font to bring down the value of all of your responsive variable so you’re not left with one line of copy per scroll.

Likewise, as we saw above, at smaller breakpoints, copy can get TINY. Do the inverse and drop down the base font at smaller breakpoints to increase your responsive values.

But there you have it! Play around, you might want to reserve this technique for only headings meant to be really impactful and keep the traditional fixed pixel value for everything else. Go ahead and create some beautiful interfaces.

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →

What’s Next →