Vertical rhythm is an important concept in web design and development. It makes the page and typography feel consistent and visually pleasant. Maintaining the rhythm across the site, especially on larger collaborative projects, can be quite a challenge. With SASS, LESS and now the CSS variables, configuring and maintaining the vertical rhythm has never been easier. In this article, we are going to cover the very basics of vertical rhythm and how to implement it using CSS variables and CSS calc
function.
Vertical rhythm basics
Vertical rhythm is usually used on following CSS properties:
- Typography -
line-height
- Spacing -
padding
(top and bottom),margin
(top and bottom) - Offsets -
top
,bottom
- Size -
height
,min-height
,max-height
Notice how we don't use vertical rhythm for font-size
. Modular scale is usually used for font sizes in typography. Vertical rhythm is only used for spacing and vertical size.
First off, we need to determine the rhythm unit. This will act as a base for multiplication for calculating vertical ryhthm. Since vertical rhythm is tied with repetition, and the most repetitive spacing on any website is a line-height
of body
element, the base line-height of a page. We'll use this base line-height as rhythm-unit.
html {
/* Set parent font size */
font-size: 18px;
}
body {
/* Set base line-height */
line-height: 1.778rem;
}
Note that we are using px
value for easier calculation, it's recommended to use relative values wherever you can. From this configuration, we can calculate rhythm unit value: Rhythm unit = 18px * 1.778rem = 32px
. Alternatively, we can check the line-height
of the body
element in element inspector.
On the image, we can see the baseline grid of 32px (1 rhythm unit) and how the text fits nicely into it. Notice how the heading's line-height is exactly 2 times the base rhythm unit. That means that heading's line-height has rhythm unit multiplier of 2 (with a bottom margin of 1 rhythm unit).
Rhythm unit multipliers
Of course, we can't have only one spacing value. This is where rhythm unit multipliers come in.
html {
/* Set parent font size */
font-size: 18px;
}
body {
/* rhythmUnit = 32px */
line-height: 1.778rem;
}
.spacing__vertical--1 {
/* 1x rhythmUnit = 32px */
padding-bottom: 1.778rem;
}
.spacing__vertical--2 {
/* 2x rhythmUnit = 64px */
padding-bottom: 3.556rem;
}
.spacing__vertical--3 {
/* 3x rhythmUnit = 96px */
padding-bottom: 5.334rem;
}
We have our basic classes for spacing which are calculated by multiplying the rhythm unit by 2, 3, 4, etc. But these classes are not flexible enough and they won't cover all of the use-cases for vertical rhythm. That's why we will create CSS variables (also can be done in SASS and LESS) to store and dynamically calculate the vertical rhythm values.
:root {
/* Base values */
--typography__fontSize: 18px;
--spacing__rhythmUnit: 1.778rem; /* 1.778rem * 18px = 32px */
/* Calculations */
--spacing__vertical--1: var(--spacing__rhythmUnit);
--spacing__vertical--2: calc(2 * var(--spacing__rhythmUnit));
--spacing__vertical--3: calc(3 * var(--spacing__rhythmUnit));
}
html {
font-size: var(--typography__fontSize);
}
body {
line-height: var(--spacing__vertical--1);
}
.spacing--default {
padding-bottom: var(--spacing__vertical--1);
}
.button--default {
height: var(--spacing__vertical--2);
}
.heading--primary {
line-height: var(--spacing__vertical--3);
}
We have improved upon the previous example and created reusable variables that we can use for all mentioned use-cases (typography, spacing, offset, height, etc.). By using these variables, we can ensure the consistent vertical rhythm of all elements on the website. But we need to keep in mind when we add some CSS rules (like borders) that push the content down and don't have to adhere to rules of vertical rhythm.
Compensating for borders
When we add vertical (top or bottom) borders to an element, they add to the overall height of the element and push the content down. This also affects our vertical rhythm (if border width is not in vertical rhythm value) and we have to compensate for adding vertical borders by either reducing the rhythm value of vertical padding
, margin
or line-height
(if element has no padding or margin).
:root {
/* Base values */
--typography__fontSize: 18px;
--spacing__rhythmUnit: 1.778rem; /* 1.778rem * 18px = 32px */
--border__width--default: 0.111rem; /* 2px */
/* Calculations */
--spacing__vertical--1: var(--spacing__rhythmUnit);
--spacing__vertical--2: calc(2 * var(--spacing__rhythmUnit));
--spacing__vertical--3: calc(3 * var(--spacing__rhythmUnit));
}
html {
font-size: var(--typography__fontSize);
}
body {
line-height: var(--spacing__vertical--1);
}
.heading--primary {
border-bottom: var(--border__width--default) solid #aaa; /* 2px */
padding-bottom: calc(
var(--spacing__vertical--1) - var(--border__width--default)
); /* 32px - 2px */
line-height: var(--spacing__vertical--3); /* 96px */
}
Taking a look at the .heading--primary
class, we can see that we have set a bottom border, padding and line-height. Since we have padding, we are going to compensate for added bottom border by reducing the width of the border from bottom padding.
If we assume that the heading takes one line of text, have the following calculation of the element's height: 2px + (32px - 2px) + 96px = 128px
which is equal to 4 times the vertical unit.
Top comments (1)
Hi! Great subject, thanks! I have a question though, why did you set the line-height property exactly to 1.778rem? Can this value be something else? I got that 18px * 1.778rem equals 32px which is our 1 vertical rhythm. Can I adjust this according to my fonts, right? I guess I can put 16px for the base font size, and 1.3rem for the vertical rhythm if that's my design case. Cheers!