Using Sass & Compass Vertical Rhythm to set up typography defaults in a project.

Good typography is the key to a successful web interface. It shapes the aesthetics and gives life to it’s content. This post is a overview of the typographic base used in some of my projects written in Sass and using Compass for it’s superb vertical rhythm mixins.


Before reading one must be aware of a newer, updated version of this article that utilises Sass Maps to achieve the same effect.

The basic variables for the type settings are the $base-font-size, $base-line-height and $rhythm-unit. They are set in pixels for the Compass vertical rhythm to use as default values, then later on coverted to rems with pixel fallback (available in Compass 1.0.0.alpha).

Setting up the basic variables.

// The base font size
$base-font-size: 18px;
// Base line height
$base-line-height: 30px;
// Rhythm unit (Compass vertical rhythm)
$rhythm-unit: “rem”;

Pretty straightforward, right? Let’s set up the basics — base font size, it’s weight and color.

$base-font-family: “Source Sans Pro”, “Helvetica Neue”, Helvetica, Arial, sans-serif;
$base-font-weight: 400;
$base-font-color: #303033;

Creating the type scale

From here it get’s interesting. Every project has a typographic hierarchy, depending on the scale of the project, setting the sizes as variables is a practical way of keeping track (and changing, adjusting) of the type sizes at any moment.

You can use the http://modularscale.com/ to generate your font sizes. In this example, I used the perfect fourth (3:4) ratio with the base font size of 18px. Using the generator gives us a nice list of sizes, we round them up and get — 10, 14, 18, 24, 32, 43.

Now that we have our type scale, we can add them to the variables. For my projects I use the tiny, small, base, medium, large and xlarge sizes. You could add more sizes to the mix, but you should consider is it really necessary and will the users see a difference in two headings that are 2-3px different?

Always set up the leading for a every font size to avoid line collisions in the longer, multi-line paragraphs and headings. The fonts are set pixels, and then converted to rems with pixel fallbacks via Compass vertical rhythm @include adjust-font-size-to() mixin. The leading size depends on your typeface, and you should test the headings and the paragraphs before making the decisions. The @include adjust-leading-to() mixin takes care the rem calculations (and pixel fallbacks) for you.

$tiny-font-size: 10px;
$tiny-font-leading: 0.75;
$small-font-size: 14px;
$small-font-leading: 0.75;
$base-font-size: 18px;
$base-font-leading: 1;
$medium-font-size: 24px;
$medium-font-leading: 1.25;
$large-font-size: 32px;
$large-font-leading: 1.25;
$xlarge-font-size: 43px;
$xlarge-font-leading: 1.5;

Generating the type scale

For bigger projects, I create a really simple Sass mixin with all my type sizes to make it easy to inject the sizes in other elements. Depending on the desired type size, it uses the adjust-font-size and adjust-leading-to with the corresponding variables for different sizes.

@mixin typeSize($size) {
@if $size == "tiny" {
@include adjust-font-size-to($tiny-font-size);
@include adjust-leading-to($tiny-font-leading);
}
@if $size == "small" {
@include adjust-font-size-to($small-font-size);
@include adjust-leading-to($small-font-leading);
}
@if $size == "base" {
@include adjust-font-size-to($base-font-size);
@include adjust-leading-to($base-font-leading);
}
@if $size == "medium" {
@include adjust-font-size-to($medium-font-size);
@include adjust-leading-to($medium-font-leading);
}
@if $size == "large" {
@include adjust-font-size-to($large-font-size);
@include adjust-leading-to($large-font-leading);
}
@if $size == "xlarge" {
@include adjust-font-size-to($xlarge-font-size);
@include adjust-leading-to($xlarge-font-leading);
}
}

Utilising DRY principles with Sass placeholders

DRY stand for Don’t Repeat Yourself. Sass placeholders are an excellent example of the DRY philosophy. I won’t get into details on placeholders, if you haven’t used them you should, more info can be found here.

First we create the font-weight placeholders for different font weights — obviously.

// Type weights
%t-ultrastrong {
font-weight: 900;
}
%t-strong {
font-weight: 700;
}
%t-regular {
font-weight: 400;
}
%t-light {
font-weight: 300;
}
%t-ultralight {
font-weight: 200;
}

Then we create different placeholders for different sizes, and additionally the classes for every size.

// Type size variants 
%t-tiny {
@include typeSize(tiny);
}
%t-small {
@include typeSize(small);
}
%t-base {
@include typeSize(base);
}
%t-medium {
@include typeSize(medium);
}
%t-large {
@include typeSize(large);
}
%t-xlarge {
@include typeSize(xlarge);
}
.t-tiny {
@include typeSize(tiny);
}
.t-small {
@include typeSize(small);
}
.t-base {
@include typeSize(base);
}
.t-medium {
@include typeSize(medium);
}
.t-large {
@include typeSize(large);
}
.t-xlarge {
@include typeSize(xlarge);
}
// Type — headings
#{headings(4)} {
margin: 0;
}
h1 {
@extend %t-xlarge;
}
h2 {
@extend %t-large;
}
h3 {
@extend %t-medium;
}
h4 {
@extend %t-base;

Creating the placeholders gives us the possibility to use the @extend directive on any of our elements and save valuable lines of CSS and reduce repetition and redundancy. For example, if we have a paragraph in the header that need to look like an h2 we simply write the following:

header > p {
@extend %t-large
}

For all the other elements the procedure is the same.

p {
@extend %t-base;
@extend %t-light;
}
small {
@extend %t-small;
}
strong, b {
@extend %t-strong;
}

Using the @extend directive we can apply the font sizes and weights to all of our elements, and utilize the typeSize @mixin for including of the styles in the elements.

Using Breakpoint to scale the type for different devices

Text on smaller screens like smartphones and tablets is generally read from a smaller distance and the type sizes must be adjusted for a better reading experience.

I currently use the great Breakpoint-sass module for creating all sorts of breakpoints. I won’t go trough the installation process of Breakpoint, it’s fairly straightforward and well documented on their website.

To create a break point using Breakpoint-sass we simply use the breakpoint mixin, $small-screen-width is a width or a min-width of your choice.

@include breakpoint($small-screen-width)

We’ve used our modular scale to get our type size scale, but for our application we would like to make the type smaller on a device with a screen width of 420px, for example. The great part of having a modular scale is that we can shift the size scale depending on the user’s device.

Our modular scale from the beginning of the post is:

  • 10 px — tiny font size
  • 14 px — small font size
  • 18 px— base font size
  • 24 px— medium font size
  • 32 px— large font size
  • 43 px — xlarge font size

Let’s move the scale to set the base font size to 14px for small screens. We take down the font size of every (except tiny, which is tiny enough) for a modular scale level. Small becomes tiny, base becomes small etc.

  • 10 px — tiny font size
  • 10 px — small font size
  • 14 px— base font size
  • 18 px— medium font size
  • 24 px— large font size
  • 32 px — xlarge font size

I’ve restructered the mixin from the beginning of the post to utilise the Breakpoint-sass module.

@mixin responsiveTypeSize($size) {
@if $size == "tiny" {
@include adjust-font-size-to($tiny-font-size, $tiny-font-leading);
}
@if $size == "small" {
@include adjust-font-size-to($tiny-font-size, $tiny-font-leading);
@include breakpoint($small-screen-width) {
@include adjust-font-size-to($tiny-font-size, $tiny-font-leading);
}
}
@if $size == "base" {
@include adjust-font-size-to($small-font-size, $small-font-leading);
@include breakpoint($small-screen-width) {
@include adjust-font-size-to($base-font-size, $base-font-leading);
}
}
@if $size == "medium" {
@include adjust-font-size-to($base-font-size, $base-font-leading);
@include breakpoint($small-screen-width) {
@include adjust-font-size-to($medium-font-size, $medium-font-leading);
}
}
@if $size == "large" {
@include adjust-font-size-to($medium-font-size, $medium-font-leading);
@include breakpoint($small-screen-width) {
@include adjust-font-size-to($large-font-size, $large-font-leading);
}
}
@if $size == "xlarge" {
@include adjust-font-size-to($large-font-size, $large-font-leading);
@include breakpoint($small-screen-width) {
@include adjust-font-size-to($xlarge-font-size, $xlarge-font-leading);
}
}
}

Simple as that ☺ All of our type sizes have their mobile first “small-screen” equivalent. All of the headings, the paragraphs, lists and other typographic elements have two sizes — scaled on the modular scale.

This blogpost is a work in progress, and will be updated as I find out better ways of handling the typography on the web.

Let me know what you think!

Since Sass 3.3 is out I have been actively working on improving this method using Sass Maps. Stay tuned — the article is comming soon.

Follow @amlinarev for more #sass goodness.