Vertical rhythm is a typography concept to make a page easier to read. There are already a lot of posts explaining this: have a look here or here or here.

Implementing the correct sizes to maintain vertical rhythm manually is a lot of work in CSS. Fortunately, there are some solutions to make this easier using a preprocessor like SCSS. However, most SCSS solutions require you to specify which font-size/line-height you want to use by using a name (like small, medium, large) or a multiple of the base line-height (1, 2, 3...). This forces you to think about which size to use every time you apply vertical styling. Moreover, if you refactor an existing site you will have to manually re-calculate each size to use the base line-height.

An easier solution

Let's have a SCSS function round our sizes for us. This way, we can still use the sizes we are used to (px, rem) but SCSS will round them to the nearest size to keep vertical rhythm. If we have to refactor an existing site, we only have to wrap our existing sizes in function calls. If we want to revert the rounding later, we can adjust the function and our original sizes will still be there.

First, we need to define our base line-height. We also create a SCSS map that contains the base line-height in different CSS units. Don't forget to also set the base font size on your HTML tag to make sure rem sizes render correctly.

  $baseFontSize: 16px;
$baseLineHeight: 20px;
$typeScale: ( 
  'px': $baseLineHeight, 
  'rem': ($baseLineHeight / $baseFontSize * 1rem)
);

html {
  font-size: $baseFontSize;
}

Now we can define our rounding function. Give it a short name, because you will have to type it in a lot of places. The $size argument is the size you want to round. $allowSubScale is a flag that enables rounding to smaller sizes than the base line-height (more on that below).

  @function vrhythm($size) {
  @if not map-has-key($typeScale, unit($size)) {
    @error 'Size with unsupported unit passed to vrhythm function.';
  }
  $typeScale: map-get($typeScale, unit($size));

  @return max(1, round($size / $typeScale)) * $typeScale;
}

We can now use our function to define all vertical sizes in our styling. For example:

  p {
  font-size: 1rem;
  line-height: vrhythm(1.2rem);

  margin: vrhythm(1rem) 0;
}

Font sizes

We don't want to have to calculate the line-height for every font-size we use. Let's create a helper mix-in to do this:

  @function vrhythmLineHeight($fontSize) {
    @return vrhythm($fontSize * 1.2);
}

@mixin vrhythmFontSize($fontSize) {
    font-size: $fontSize;
    line-height: vrhythmLineHeight($fontSize);
}

Small sizes

Sometimes we might want to use spacing that is smaller than the base line-height. This will cause our vertical rhythm to be lost temporarily. To make sure the rest of our page aligns with the vertical rhythm again, we will need to keep the following rules in mind:

  • Our spacing should be a divider of the base line-height
  • We should use the spacing the correct amount of times to add up to the base line-height.

This simple helper function will divide the base line-height:

  @function vrhythmSubLineHeight($times) {
  @return ($baseLineHeight / $times);
}

Now we can use smaller sizes. For example, we can apply half the base line-height to the top and bottom padding of an element:

  blockquote {
  margin: vrhythm(1rem) 0;
  padding: vrhythmSubLineHeight(2);
}

Demo


908 0 0