Finding your Rhythm: Precision Baselines with Sass

At Inkling, we’re immersed in the world of digital design, but we also believe that there is much to learn from centuries’ worth of print design principles. In fact, as we iterate on the process of translating legacy print content for digital formats, we often find ways in which concepts refined in fixed layout design can apply to the world of eBook design. One of the more compelling (and often overwhelming) concepts is vertical rhythm.

Vertical rhythm has found its revival in web typography. While print designers have utilized this concept for hundreds of years, it’s become an emerging principle for web designers, thanks in part to growing web communities, better browsers, and the rise of CSS preprocessors, namely Sass. We use Sass extensively here, from scaling content patterns across hundreds of eBooks to establishing unique vertical rhythm for a single title. There are already several great articles on the principles of vertical rhythm, and some of the major Sass frameworks have incorporated rhythm tools into their codebase. Therefore, instead of repeating the theory, this article focuses on building a rhythm from the ground up with Sass so you can use these tools with confidence–or build your own!

What is vertical rhythm?

Designing with rhythm begins with a consistent vertical grid and then aligning all spacing and line-heights to that grid, creating a visually pleasing “rhythm” of positive and negative space. If you’d like a good primer on the concept, I suggest these great articles:

Now that we’ve brushed up on the concept, let’s bring on the Sass.

Setting up the rhythm

We’ll begin by creating the Sass variables and functions needed for maintaining the rhythm.

$base-font-size: 16; 

This is the default font size for our body text. All other font sizes (headings, marginalia, etc) will be based on this size. It’s important to note that the font size is set pixels (without units), but the final values will be converted to ems or rems later.

$base-line-height: 24; 

This is the default line height for our body text. Again, the pixel value will be converted into a unit-less multiple of the current font-size later.

$rhythm-unit: $base-line-height; 

The aptly named $rhythm-unit represents a single unit of our vertical rhythm. This variable will be used for our spacing values and baseline guide. We’ve set this number equal to the $base-line-height, but we’ll discover there are situations in which a smaller unit would be useful.

@function em($target, $context: $base-font-size) {     @if $target == 0 { @return 0 }     @return $target / $context + 0em; } 

The em() function is used to convert our pixel-based font sizes into em values. I’ve chosen em for my type units because I prefer to have my fonts change size when the parent element’s font size changes. You could easily replace this with a rem function that calculates sizes based on the document font size – the function would even be simpler since context isn’t needed for rems.

The target font size is divided by the base font size and then added to 0em to restore the unit. If the current context (the font size of the current element) is different than the $base-font-size, a new context can be passed as well. Thanks to Ian Young for this px to em function.

Building the baseline guide

To make sure our elements are aligning to our rhythm, we’ll create a vertical grid that matches our rhythm. This grid, known as a baseline guide, aligns with the typography baseline of the base font size. Type lovers may point out this is actually the bearing line, but there’s no reason to split hairs–the relative distance is the same. For those who want a true visual “baseline,” check out this article by Razvan Onofrei on creating a print-style baseline with Sass.

$guide-color: #FF6BA6;  @mixin baseline-guide() {     @include background-image(linear-gradient($guide-color 1px, transparent 1px));     background-size: 100% em($rhythm-unit); } 

The baseline-guide() mixin uses a linear gradient to generate a 1px line of color followed by transparency. This pattern repeats every interval of the rhythm, generating a vertical grid of baselines. Due to sub-pixel rounding, the grid will not align perfectly with certain sizes and should only be used as a reference, not a holy truth.

Next we apply our $base-font-size, $base-line-height and baseline-guide() to the html tag, creating the foundation of our rhythm.

html {     font-size: $base-font-size*1px;     line-height: $base-line-height/$base-font-size;     @include baseline-guide; } 

Here’s what we’ve built so far. I’ve added some text to illustrate the alignment.

See the Pen dLCft by me (@adispezio) on CodePen.

Setting font sizes and line heights

The next step is to make sure our typography scale fits nicely into our rhythm. The font-size() mixin below sets the font size in ems with pixels as a fallback. If $line-height is set to true, the mixin will also generate a line height that fits into a multiple of the $rhythm-unit. This will ensure that the vertical rhythm is not disrupted by the change in font size. This mixin was created by Philipp Kreutzer and later refined by Harry Roberts.

@mixin font-size($font-size, $context: $base-font-size, $line-height: false){     font-size: ($font-size)*1px;     font-size: ($font-size / $context)*1em;     @if $line-height == true{         line-height:ceil($font-size / $rhythm-unit) * ($rhythm-unit / $font-size);     } } 

We can then apply the font-size() mixin to our type elements to ensure they match our rhythm. For example, let’s change the font size of the <h2> tag.

h2 {     @include font-size(32, $line-height: true); } 

You’ll notice that with $line-height set to true, the <h2> takes up exactly 2 rhythm units of line height, since this is the closest multiple to the rhythm that will fit that particular font size.

See the Pen wFjiA by Anthony DiSpezio (@adispezio) on CodePen.

Setting margins

The vertical spacing between elements is applied using margin-bottom. Adding margins in only one direction gives us better consistency by reducing the chance of double spacing or unwanted margin collapse. Harry Roberts has a great article covering this topic in depth.

h2 {     margin-bottom: em($rhythm-unit, 32); } 

Again, we’ll use our $rhythm-unit to make sure the margin equals exactly 1 rhythm unit. Notice I had to pass the $context of the <h2> since the font size is larger than the $base-font-size. This step would not be needed if using rems.

See the Pen dIAas by me (@adispezio) on CodePen.

Compass accomplishes the same technique using shorthand mixins. The trailer() and leader() mixins allow adding multiples of the $rhythm-unit as top or bottom margin. This approach is definitely effective, but is too much abstraction for my taste. I’d rather see the margin properties than a set of @includes.

So my type is perfect now, right?

Sadly, no. As with many conceptual principles, vertical rhythm is not immune to real-world problems that can make implementation a pain.

  • Uncommon base line-heights can complicate the math, creating too much or too little space. Often the multiple up to the next full line-height is too much and creates awkward space.
  • Image heights rarely match a multiple of the base line-height, so a full page tends to lose its rhythm when viewing the page in its entirety. Here’s a neat solution by Daniel Eden.

In some of my more “perfect” attempts, I’ve seen this strict vertical rhythm be VERY successful. But the other half of the time, the rigidity of the math creates technically accurate rhythm that just feels visually unbalanced. In the example below, notice how the <h2> fits our rhythm, but the line height is way too large.

See the Pen ChaKi by Anthony DiSpezio (@adispezio) on CodePen.

Mitigating the pain

One way to use the vertical rhythm logic and allow for more line height flexibility is to set the $rhythm-unit to a multiple smaller than the actual $base-line-height of your page.

For example:
If your $rhythm-unit is 24, this will only allow clean line height multiples at 24px, 48px, 72px, etc.

But if you change the $rhythm-unit to 12 you get more multiples to work with (12px, 24px, 36px, 48px, etc). The $base-line-height would still be 24, but it is now 2x our $rhythm-unit (12).

See the Pen psHED by me (@adispezio) on CodePen.


Together we’ve built a solid rhythm for our page. The takeaway example below adds a few bells and whistles:

  • The baseline guide was moved to the ::after element of the “ tag, allowing overlaid guides when using background colors.
  • Heading rhythms were built into a map and parsed with an @each loop.
  • The guide supports a half-baseline mark with a different color.
  • The body now sets the base font size to 1em and adds 1 rhythm unit of margin to all side.

See the Pen GxiCl by Anthony DiSpezio (@adispezio) on CodePen.

Tools to keep your rhythm

Now that you know how Sass-based rhythms work, I recommend exploring some of the great Sass toolkits and frameworks that have their own tools for vertical rhythm:

The Compass framework contains a library of powerful functions, mixins and other tools to make Sass development even more fun. The vertical rhythm module contains many of the features we discussed and more.

Typeplate is a framework starter kit for generating robust typographic styles. Typeplate takes the concepts we’ve covered here and extends them into all sorts of useful design patterns.

Inuit is a framework for Sass projects. Inuit has it’s own vertical rhythm mixins and functions, relying on the same techniques we discussed.

Typograph is a fantastic tool for exploring type rhythms and scales.

Baseline (im)perfection

With an increasing landscape of devices and viewports, it’s more important than ever to make sure our readers are consuming high calibre content, both in subject and style. Just because the average user may not consciously see bad rhythm doesn’t mean we, as designers, can be lazy about it.

Does this mean always having a perfect rhythm is the only way to make beautiful content? I don’t think so. Sometimes, breaking the rhythm can lead to exceptional layouts, simply by listening to your design instincts. Keeping a keen eye on design and respecting visual flow will lead to a better reading experience and happier readers.