Skip to content
Home

Some notes on using clamp and vw to set font size

| Comments

There are many ways to set a base font size on your website. When I wrote about this last year, I was using media queries to up the base font size as the screen got wider. This works well enough, but poses three problems.

Firstly, it’s verbose. You have to write a separate media query whenever you want to change the font size. Secondly, it results in font sizes that jump suddenly when an arbitrary screen width is reached – a single font size will apply across a broad pixel range, doing a lot of lifting. Take this example:

html {
  font-size: 118.75%;
}

@media screen & (min-width: 30em) {

  html {
    font-size: 125%;
  }
  
}

@media screen & (min-width: 60em) {
  
  html {
    font-size: 150%;
  }
  
}

@media screen & (min-width: 80em) {
  
  html {
    font-size: 175%;
  }
  
}

Assuming an em equates to 16px, the browser will calculate the following base font sizes:

Browser width (px) Calculated base font size (px)
479 19
480 20
959 20
960 24
1279 24
1280 28

You’ll note the browser uses the same base font size at widths of, say, 490px and 950px, but will increase it by 4px when it reaches 960px. This seems an unsatisfactory experience. Wouldn’t it be better if the font size increased more gradually in relation to the screen width? This is possible using more media queries, but we already have three.

Our last problem betrays a way of thinking rooted in the early days of mobile-first, responsive design. Our breakpoints are meant to kick in whenever a different type of device is used, or when a visitor flips their device orientation. In this case, it’s an attempt to provide different font sizes for mobiles, tablets/laptops then desktop monitors.

Of course, it’s impossible to know what type of screen a visitor is using. Some laptop – or even mobile phone – screens will contain more pixels than a desktop monitor. If we were able to relate our font size more closely to the screen width we’d no longer create arbitrary breakpoints for mobile, tablet and desktop monitors.

And we can do this in a single CSS declaration. Here’s what I’m using at the time of writing:

html {
	font-size: clamp(var(--min-font-size), var(--font-size), var(--max-font-size));
}

Without custom properties it’s…

html {
	font-size: clamp(118.75%, 1.9vw, 175%);
}

Which probably computes to…

html {
	font-size: clamp(19px, 1.9vw, 28px);
}

The clamp property has three values:

  • A minimum value (in this case 118.75%, which will most likely compute to 19px)
  • A desired value (in this case 1.9vw, i.e. 1.9% of the browser viewport width)
  • A maximum value (in this case 175%, which will most likely compute to 28px)

So we’re setting the base font size in a nuanced way – it’ll be 1.9% of the browser viewport width, but never below 19px and never above 28px.

Things to bear in mind when using vw

Make sure you test your website scales predictably up to 200% with cmd + in MacOS and ctrl + in Windows and Linux-based distros. If it doesn’t, you’ll have an accessibility problem for users who alter default text sizes.

Browser support for clamp and vw is good, and you can offer a fall back by setting a normal font size before using clamp. For example, my complete font size CSS is:

html {
	font-size: 118.75%;
	
	// If the browser (e.g. IE) doesn’t support clamp the following will be ignored and font-size set to 118.75%
	
	font-size: clamp(var(--min-font-size), var(--font-size), var(--max-font-size));
}

clamp and vw work well. Setting predictable looking type across different devices is difficult using any method because there are so many variables involved. On this laptop (an early 2015 MacBook Pro with a 13-inch Retina screen and a reported 2560 × 1600 resolution), if I use a 2.1vw I get a 27px font size when the browser is maximised, which is a bit like being battered around the eyeballs. On my seemingly similar work laptop (a 2018 MacBook Pro with a 15-inch Retina screen and a 2880 × 1800 reported resolution) I get a 28px font size, but that seems just right. Reducing the suggested size to 1.9vw results in a 24px on the older Pro, which is 👍 – to my eyes, at least.

It’s worth checking how your type scales on different devices and by resizing your browser as much as possible. You may find the actual scaling takes place within a fairly narrow range of widths because the min and max values are restrictive, or the vw maths just work out that way. Whether this is a problem is a matter of judgement. For example, setting lower and upper limits of 19px and 21px may be the best approach in a multi-column layout, while a single column allows more freedom.

As with all typography, it’s a mixture of art, science and experimentation. Disparate settings affect each other. At the moment, I’m liking large sans serifs with a short measure and a tight leading; finding a calculation that (maybe) works with that combination has taken some fine tuning.

Add a comment

Required fields marked *. I won’t publish or share your email address.

Comments

None 🦉.