Vertical Rhythm with Compass

Vertical rhythm and baseline grids are age old tools used by designers to help aid the placement of content within a layout. This post is focused on the 'how' not so much the why. If you don't know the 'why' I highly suggest checking out the following resources.

Implementing vertical rhythm on the web involves manipulating the CSS properties that govern vertical spacing: font-size, line-heights, padding, margins and borders. Doing so in an accessible manner (using relative font-sizes) used to be a painstaking process, involving tedious calculations across a variety of font-size contexts. The Vertical Rhythm tools in Compass make it easy. However, despite Compass' amazing documentation, I did find a bit of a learning curve with Vertical Rhythm. Hopefully after reading this, you'll be able to dive right in and harness the delicious power of these tools right away.

What does Vertical Rhythm do?

Vertical Rythym is a set of functions and mixins that help calculate line heights, vertical padding, margins and border thickness values based on a base line height and font-size to conform to a baseline grid.

So how does it work? Let's say you want a base font size of 16px and baseline grid of 24px. To get started with vertical rhythm you need to import the Vertical Rhythm library and set the following variables.

@import "compass/typography/vertical_rhythm";
 
$base-font-size: 16px;
$base-line-height: 24px;

Vertical rhythm will use these variables in its calculations but hasn't really done anything yet. We first need to establish our baseline. We do this by inlcluding an aptly named mixin called establish-baseline.

@include establish-baseline;

All this mixin does is set a default font-size and line-height on our <html> tag. But it does so using relative units. The above mixin compiles to this CSS:

html {
  font-size: 100%;
  line-height: 1.5em;
}

16px is the default font size for most browsers, so 100% = 16px. A relative line-height is always relative to the font-size of the current element, so in this case the line-height is set to 1.5 em ( 1.5 * 16px = 24px). Now all of the elements that don't have font-size set by browser agents, will conform to our baseline grid. That's cool... I guess.

The fun starts when you begin setting font sizes on other elements. Let's say we want to make our <h1>s 42px. We do so using the adjust-font-size-to mixin.

h1 {
  @include adjust-font-size-to(42px);
}

This does a couple things. First it sets our font-size relative to our element's container, which in most cases will be our $base-font-size. So we get something like:

font-size: 2.625em;   // 2.625 * 16px = 42px
But here is where the magic happens. Vertical Rhythm also sets line-height to a factor of our baseline grid, larger than the font-size. So in the case of our 42px font-size, it sets the line-height to 48px or 2 baseline units or technically speaking
 line-height: 1.142857143em;  // 1.142857143 * 42px = 48pxish
I think that's sweet. Vertical Rhthym is making some pretty easy calculations on our behalf, but those add up real quick. During a recent talk Ken gave expounding on the benefits of SASS, an attendee asked *"Why would I use SASS? It's just 5th grade math."* To which I would have liked to reply *"It's actually 6th grade math with a bit of 7th grade algebra. I still don't want to do it."* I digress.

So what happens when you want to go down in font size? Let's say 12px on some meta data. What we learned above would result in a line height of 24px, which would be akwardly large. Easy! If we want a line height of 16px so that every 3rd line of our meta data lines up with every 2nd baseline. We just pass the desired number of rhythm units to the same mixin. In this case:

.meta {
  @include adjust-font-size-to(12px, 2/3);
}

Note: Instead of 2/3, you could use .666, but that is the decimal of the beast. Not to mention more 6th grade math.

To further complicate things, what if that meta style was in some sort of sidebar component in which the font size had already been adjusted to 14px. Well, I would first say "Don't set font-sizes on containers. You will regret it later." Followed by "Just pass the container's font-size as the from-size parameter. Like so..."

.meta {
  @include adjust-font-size-to(12px, 2/3, 14px);
}

BAM! Vertical rhythm adjusts its math accordingly.

Margins and Padding

Margins and padding affect vertical rhythm just as much as line-height. There are mixins to handle them as well. The first is the mother-load rhythm mixin. I say mother-load because this sets all your vertical padding and margins at once. Using our 42px <h1> example from earlier we might do something like:

h1 {
  @include rhythm(3, 1, 0, 2, 42px);
}

Which compiles to:

h1 {
  margin-top: 1.714285714em;    // 3 units or 72px
  padding-top: .571428571em;    // 1 unit or 24px
  padding-bottom: 0;            // 0 units 0px
  margin-bottom: 1.142857143em; // 2 units or 48px
}

I actually find the above mixin overkill in most cases and prefer to use the rhythm function instead. Note that this is a function not a mixin as shown above. Mixins begin with @include and usually spit out one or more css rules. Functions are similar but return values that are used within a css rule. Let's say I just want to set all 4 margins on my <h1> with a combination of rhythm units and standard CSS notation.

h1 {
  margin: 0 auto rhythm(3, 42px);
}

Which compiles to:

h1 {
  margin: 0 auto 1.714285714em;
}

More often than not, I'm setting margins and padding on containing elements and can omit the second parameter causing Vertical Rhythm to evaluate based on the base font-size. Another reason to not set font sizes on containers.

Borders

The last mixins I'll talk about are those that deal with borders. A 2px top border can throw off the rhythm of all the following elements if you don't compensate for the space it takes up. This is where the leading-border and trailing-border mixins come in handy. These allow you to set top or bottom padding along with your border widths to keep things on rhythm. Let's see how it works.

blockquote {
  @include leading-border(2px, .5);
  @include trailing-border(2px, .5);
}

Compiles to:

blockquote {
  border-top-width: .125em;          // 2px
  border-bottom-width: .125em;   // 2px
  padding-top: .625em;                   // 10px
  padding-bottom: .625em;           // 10px
}

Now we have a blockquote with top and bottom borders and padding that will maintain rhythm. The borders and padding combine for a total of 12px top and bottom— half of our baseline unit. That's pretty neat!

There are many more mixins, functions and variables in the Vertical Rhythm library to take advantage of. I've outlined the ones I use most often.

I'll leave you with one last tip that I use all the time. At Aten, we typically design with a smaller baseline grid than 24px as outlined above. More often than not, we use a 6px baseline grid. This has an advantage when working with Vertical Rhythm. Setting our $base-line-height variable to 6px helps avoid the awkwardly large line-heights at certain font-sizes. Consider adjusting an element's font-size to 24px. If the $base-line-height is also set to 24px, your line-height becomes 48px which is probably too sparse. With a $base-line-height of 6px your line height will be set to 30px, which is probably more readable. Keep in mind you can always adjust your line-height manually while maintaining rhythm with the adjust-leading-to mixin.

Setting $base-line-height smaller than $base-font-size will result in overcrowded default text. This is easily solved by including the adjust-leading-to mixin after initially establishing your baseline like so:

$base-font-size: 16px;
$base-line-height: 6px;
 
@include establish-baseline;
 
html {
  @include adjust-leading-to(4);
}
This will set a nice default font-size of 16px with a 24px line-height. Enjoy your newfound rhythm!
Code Design

Read This Next