Pure CSS Vertical Rhythm


For this website, I wanted to work with a vertical rhythm. There are plenty of services, like Gridlover and Typescale to automatically generate a vertical rhythm system, and that’s all well and good. But I wanted a challenge.

It’s pretty straight forward to build or generate a vertical rhythm system using a pre-processor like SCSS or Stylus. But how about with vanilla CSS? CSS has come a really long way in the last 10 years with a raft of functionality like variables (CSS Custom Properties), measurement functions, etc.

The vertical rhythm on this site is a work in progress, so here’s how I’ve done it so far.

Establishing the parameters

:root {
  /* Type scale ratios */
  /* Found: https://gridlover.net/try */
  --type-ratio__minor-second: calc(16/15);
  --type-ratio__major-second: calc(9/8);
  --type-ratio__minor-third: calc(6/5);
  --type-ratio__major-third: calc(5/4);
  --type-ratio__perfect-fourth: calc(4/3);
  --type-ratio__augmented-fourth: 1.414;
  --type-ratio__perfect-fifth: calc(3/2);
  --type-ratio__golden-ratio: calc(1.618/1);

  /* The unitless line-height of the root, or `html` element. */
  --vr-line-height: 1.618;

  /* The base font size of the root element that establishes our 1rem unit. */
  --vr-base-font-size: 16px;

  /* For fun, lets also work wiht a configurable type scale. */
  --vr-type-scale: var(--type-ratio__perfect-fourth);

  /* And finally, the basic fixed height value of 1 unit of the vertical rhythm. */
  --vr-unit: calc(var(--vr-base-font-size) * var(--vr-line-height));

  /* Vertical rhythm-aware spacing helpers. */
  --vr-spacing-1x: calc(1rem * var(--vr-line-height));
  --vr-spacing-2x: calc(2rem * var(--vr-line-height));
  --vr-spacing-3x: calc(3rem * var(--vr-line-height));
  --vr-spacing-4x: calc(4rem * var(--vr-line-height));
  --vr-spacing-5x: calc(5rem * var(--vr-line-height));
  --vr-spacing-6x: calc(6rem * var(--vr-line-height));
  --vr-spacing-7x: calc(7rem * var(--vr-line-height));
  --vr-spacing-8x: calc(8rem * var(--vr-line-height));
  --vr-spacing-9x: calc(9rem * var(--vr-line-height));
  --vr-spacing-9x: calc(9rem * var(--vr-line-height));
  --vr-spacing-10x: calc(10rem * var(--vr-line-height));
  --vr-spacing-11x: calc(11rem * var(--vr-line-height));
  --vr-spacing-12x: calc(12rem * var(--vr-line-height));

  font-size: var(--vr-base-font);
  line-height: var(--vr-unit);

body {
  font-size: 1rem;
  line-height: var(--vr-unit);

Visualizing the system

Before I forget, we need a way to visualize this system, so I created a utility to render the configurable vertical rhythm. Just add this [debug-vr] attribute to your body element (or any element, really).

[debug-vr] {
  --__vr-debug-fg: color-mix(in hsl, cadetblue, transparent 50%);
      to bottom,
      var(--__vr-debug-fg) 1px,
      transparent 1px

  position: relative;

  &::after {
    content: '';
    background: var(--__vr-debug-bg);
    background-size: 100% var(--vr-unit);
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 100;
    position: absolute;
About the author

Hi there! My name is Spencer and I’m a Web developer with a passion for building User Interfaces and all things tech. In my free time, I enjoy spending time with my wife and our 4 dogs, as well as playing guitar and exploring the world. I am also a lover of science and enjoy learning about all manner of nerdy topics.