Easy Responsive Headings using CSS Variables, VW, and Calc

Peter Makes Websites
3 min readAug 7, 2021

Defining breakpoints and all that for headings can be quite time-consuming. As a lazy person, I’ve developed a way to get around this conundrum that’s just kind of a one-off for each website and then you never really need to touch heading sizes again:

You can replace h1, h2, h3, below with classes of course like .heading-one, .heading-two, .heading-three in case you only want to apply this to certain headings.

h1 { --multiplier: 1; }
h2 { --multiplier: 0.8; }
h3 { --multiplier: 0.5; }
h1, h2, h3 {
--minfont: 26px;
--vwmultiplier: 2.3;
font-size:calc(calc(calc(1vw * var(--vwmultiplier)) * var(--multiplier)) + var(--minfont));
}
@media (min-width: 992px) {
h1, h2, h3 {
font-size:calc(calc(calc(var(--vwmultiplier) * 9.92px) * var(--multiplier)) + var(--minfont));
}
}

This takes advantage of vw (viewport width) as a means to determine font size responsively. If we used vw alone (for example set h1 to 2vw), then the size would be responsive, but we would encounter two problems.

  1. The font will get super tiny when the window gets small.
  2. The font will get super big when the window gets big.

So we need to use some fancy math to deal with this. It looks kind of complicated but it’s actually pretty simple. First, we have our minfont variable, which defines the smallest we want any heading to get.

In the website I made this for, my body text size was 22px. The smallest I want any heading to get was 26px. So I set it to 26px. Simple.

Second, every heading size has a unique multiplier that gets multiplied with 1vw. This is what makes one heading slightly bigger than the others. That way, 26px is basically the “baseline” for every heading size, then each headings unique multiplier determines how they grow differently proportional to each other.

h2 { --multiplier: 0.8; }

Then there’s a global multiplier. The following bolded 2.3 (vwmultiplier) defines to what extent we want all the headings to grow proportionally to vw from the baseline.

  --vwmultiplier: 2.3;
font-size:calc(calc(calc(1vw * var(--vwmultiplier)) * var(--multiplier)) + var(--minfont));

So, the end result is vwmultiplier is multiplied with 1vw, then multiplied with the unique headings multiplier, and then…

--

--

Peter Makes Websites

Sharing my experience of web & app development with the world