Create a vertical rhythm system in 10 lines of CSS

No tricks, no gimmicks, just straight-up vanilla CSS with 3 custom properties to create a vertical rhythm system to use on all your projects.

Vertical rhythm in 10 lines of css?

Many designers like to use a system such as GridLover.net when creating the vertical rhythm for their designs. This allows them to set a base font size, line height, and a scale factor and then "magically" creates the CSS you need for your vertical rhythm.

When looking at GridLover today, I was thinking "surely with modern CSS, especially custom properties/variables we could create a version of this to use as a vertical rhythm starterkit”.

What was my Desired Outcome?

Designers tell us the base font size is X, and the line height is Y, and the scale is Z. We then put those into CSS variables and the vertical rhythm is ready. 

How to create a vertical rhythm with CSS and custom properties

First off, let's set our three properties, followed by the styles for the body element.

:root {
  --font-size: 16px;
  --line-height: 2;
  --scale-factor: 1.5;
}
body {
  font-family: sans-serif;
  font-size: var(--base-font-size);
  line-height: var(--line-height);
}

All very basic so far, but that amount gets us a long way towards our finished product. That will cover line-height for the whole site and font sizes for everything except our headings.

Next, we'll set our headings, working from h1 to h6, with h4, h5, and h6 all having the same size as the base font size. We can differentiate them via styles, but I don't want any item on the page using a smaller font size than what the p tag will be using.

Since h4, h5, and h6 are all going to have the same font size as the p tag, we can add those to where the body element is being styled.

body,
h4,
h5,
h6 {
  font-size: var(--base-font-size);
  line-height: var(--line-height);
}
body {
  font-family: sans-serif;
}

I've moved the body font-family to its own declaration so it does not affect the heading styles (remember, we're only interested in vertical rhythm here, not font-families/colors/etc).

Now let's look at the headings. If you look at GridLover's outputted CSS, you'll see that h3 is equal to the base-font-size multiplied by the scale-factor, and h2 is equal to h3 multiplied by the scale-factor, and finally h1 is equal to h2 multiplied by the scale-factor. That can't be too hard to replicate in CSS with calc, can it?

h3 {
  font-size: calc(var(--base-font-size) * var(--scale-factor));
}

That's our h3 taken care of. Now if we multiply that by the scale-factor again, we'll have our h2. And then multiply that h2 result by the scale factor, we'll have our h1. Simple.

h2 {
  font-size: calc(var(--base-font-size) * var(--scale-factor) * var(--scale-factor));
}
h1 {
  font-size: calc(var(--base-font-size) * var(--scale-factor) * var(--scale-factor) * var(--scale-factor));
}

That's it. We have our vertical rhythm now.  Could we make the CSS a bit tidier? Sure, when pow() is available in all browsers, we could do something like this:

h1 {
  font-size: calc(var(--font-size) * pow(var(--scale-factor), 3);
}
h2 {
  font-size: calc(var(--font-size) * pow(var(--scale-factor), 2);
}
h3 {
  font-size: calc(var(--font-size) * var(--scale-factor));
}

This is the equivalent of saying h1 equals the base-font-size multiplied by the scale-factor to the power of 3; h2 equals the base-font-size multiplied by the scale-factor to the power of 2. This is currently only available in Firefox, but is part of the CSS Values and Units Module Level, so hopefully it will have full browser support soon.

In the mean time, we can probably make our code a little tidier, or at least a little easier to read, by reassigning the value of scale-factor for each of our properties.

h1,
h2,
h3,
h4,
h5,
h6 {
  --scale-factor-calculated: var(--scale-factor);
  font-size: calc(var(--font-size) * var(--scale-factor-calculated));
}
h1 {
  --scale-factor-calculated: calc(var(--scale-factor) * var(--scale-factor) * var(--scale-factor));
}
h2 {
  --scale-factor-calculated: calc(var(--scale-factor) * var(--scale-factor));
}
h3 {
  --scale-factor-calculated: calc(var(--scale-factor));
}
h4
h5,
h6, {
  --scale-factor-calculated: 1;
}

Now we have some very tidy CSS that says all our headings will use the exact same font-size property - the base-font-size multiplied by a new variable called --scale-factor-calculated. Then for each of the heading elements, we set what --scale-factor-calculated equates to.

Here's the full CSS, followed by a CodePen to see it in action.

:root {
  --base-font-size: 16px;
  --scale-factor: 1.5;
  --line-height: 2;
}
body {
  font-family: sans-serif;
  font-size: var(--base-font-size);
  line-height: var(--line-height);
}
h1, h2, h3, h4, h5, h6 {
  --scale-factor-calculated: var(--scale-factor);
  font-size: calc(var(--base-font-size) * var(--scale-factor-calculated));
}
h1 {
  --scale-factor-calculated: calc(var(--scale-factor) * var(--scale-factor) * var(--scale-factor));
}
h2 {
  --scale-factor-calculated: calc(var(--scale-factor) * var(--scale-factor));
}
h3 {
  --scale-factor-calculated: calc(var(--scale-factor));
}
h4, h5, h6, {
  --scale-factor-calculated: 1;

 

See the Pen Vertical Rhythm in Vanilla CSS by Mark Conroy (@markconroy) on CodePen.

 

Filed Under:

  1. CSS