Typography with Compass

In the last chapter we looked at how we could use Sass to help us implement a way of changing our entire typography style based on which font family we wanted to use. It may not be something that is necessary or useful in the majority of projects, but it allowed us to look at using Sass to solve a particular problem.

Compass, on the other hand, is designed to give us the tools and design patterns we need to overcome many of the common problems that we face on most of our web designs. Compass offers helpers that can be employed to tackle unique problems. Compass includes functions to help solve complex math problems, or accessibility issues with its color contrast and text functions. However, Compass also helps us solve complex design challenges such as setting a base typography grid and maintaining vertical rhythm throughout a design.

What is vertical rhythm?

Essentially, vertical rhythm is the alignment of your text and other horizontal elements on your page. Its determining factors are font size, line height, margin, and padding. If you've ever had a floated image that your text was wrapping around and wondered why there was too much space below the image...that's bad vertical rhythm.

Tip

You should always use font size, line height, margin, and padding to give your elements height. If you are using the height property for anything more than images and SVG elements, you will run into problems. Your content should always dictate its containing elements' height, never the other way around.

To see vertical rhythm in action, we'll need some HTML to work with. Luckily for us, we already have some from the last chapter. Copy the index.html file from the ch02 folder into the ch03 folder and open it in your text editor.

Next, we need some styles. Right now, our HTML is linking to css/style.css, which doesn't exist. So we'll need to update it to use our current stylesheet, which Compass created for us, located at assets/css/screen.css:

<link href="assets/css/screen.css" rel="stylesheet"> 

Now, open index.html in your browser. You'll notice one thing immediately, all of our headings are the same size as the body text. This is due to the fact that Compass, by default, imports a reset stylesheet that actually removes much of the default styling to give a uniform experience on all browsers.

In truth, I generally find the reset.css method to be overly aggressive. I much prefer the normalize.css method, which simply reduces the differences between browsers to an acceptable average state across all major browsers. A middle ground, if you will. normalize.css leaves the default headings sizes intact and doesn't remove padding/margin from forms, lists, and so on.

However, to attain vertical rhythm, it's a good idea to remove all unwanted paddings, margins, line heights, and yes, even font sizes. So, our screen.scss file should look something like this:

// mastering-sass/ch03/scss/screen.scss 
@import "compass/reset"; 

Next, we'll copy two of our variables from our style.scss file from ch02 into our screen.scss file, at the very top of the file:

// mastering-sass/ch03/scss/screen.scss 
$base-font-size: 1rem;
$base-line-height: 1.5; 
 
@import "compass/reset"; 

Note

I always structure my main Sass file like this:

  • Variables first (which override variables using !default in the following imported files)
  • Required libraries and frameworks next (such as Compass, Bourbon, Susy, and so on)
  • Finally, partials, which contain helpers, mixins and the styles

Eventually, I end up with one main file that acts as configuration (variables) and dependencies (importing libraries and frameworks) and partials (my Sassfiles). We'll work towards this structure as we progress.

Next, we'll need to import the Compass typography helpers just below the reset. We'll also add the rule for our container div to give at a suitable max-width of 38rem and center it horizontally:

// mastering-sass/ch03/scss/screen.scss 
@import "compass/reset"; 
@import "compass/typography"; 
 
/* CUSTOM STYLES */ 
body > div { 
    max-width: 38rem; 
    margin: 0 auto; 
} 

The compass/typography import will give us access to the vertical rhythm mixins that Compass uses to establish and manage the vertical rhythm of our page. Next, we'll include the mixin that will establish our baseline grid, upon which everything else will be built. Include the establish-baseline mixin just below our imports in screen.scss, with a comment so we can easily locate it in our CSS:

// mastering-sass/ch03/scss/screen.scss 
@import "compass/reset"; 
@import "compass/typography"; 
 
/* Establish Baseline */@include establish-baseline; 
 
/* CUSTOM STYLES */ 
body > div { 
    max-width: 38rem; 
    margin: 0 auto; 
} 

Next, we'll start watching our project for changes using the compass watch command. The compass watch command must run from the directory where the config.rb file is located, mastering-sass/ch03. You don't need to specify the directories or files; this is all handled by the config.rb file that we set up when we created our ch03 folder.

From the command line we simply run the following:

compass watch

Now, in the command line, you should see warnings and errors! You'll see four warnings all ending with "must resolve to a value in pixel units", or some similar messages, and then an error along the lines of "6.25%*rem/px isn't a valid CSS value".

This is because Compass requires pixel values for the $base-font-size and $base-line-height, and we are using rems and ems (line-height: 1.5 is the same as 1.5 em). To fix this, we need to update our variables:

//mastering-sass/ch03/scss/screen.scss 
$base-font-size: 16px;
$base-line-height: $base-font-size * 1.5; // 16px * 1.5 = 24px

Now our CSS should compile, and inside our screen.css you can find the comment with the content created by the establish-baseline mixin:

// mastering-sass/ch02/assets/css/screen.css 
/* Establish Baseline */ 
/* line 106, ../../../../Ruby22-x64/lib/ruby/gems/2.2.0/gems/compass-core-1.0.3/stylesheets/compass/typography/_vertical_rhythm.scss */ 
html { 
  font-size: 100%; 
  line-height: 1.5em; 
} 

As you can see, it takes care of setting our root font-size and line-height.

The next thing we need is a way to really see what we're doing. Right now, we're kind of working blind. We need some guidelines...or more appropriately, a grid. Luckily, for us Compass has just the thing.

Compass comes with an entire set of mixins and functions to help us display both column grids and baseline grids. You just include the mixin in the element where you want to display a grid. We need the grid for our entire page, so we'll place it in our HTML rule. You could also place it in the body rule.

Note

Compass grids are generally imported with the layout module using @import "compass/layout"; however, when using the typography module, the grid helpers are imported automatically as dependencies.

//mastering-sass/ch03/scss/screen.scss 
html { 
 @include baseline-grid-background; 
} 

Now when you refresh the page in the browser, you'll see our baseline grid. Right now, our main image is actually breaking our vertical rhythm ever so slightly. You'll notice the headings (even though they're all too small) and the first line all sit in the very center of the line. Then all the lines after the image are sitting nearer the top of the lines.

Vertical rhythm for images

Compass allows us to adjust elements margins and padding while keeping with our overall vertical rhythm. If we plan to leave this image where it is, we'll need reduce its height to stay within the lines. So we need to examine the height of our images and reduce them to within our line height. Let's first put the height and width attributes on our image and a class called vertical-rhythm.

In our index.html file, we'll also need to update the image:

// mastering-sass/ch03/index.html 
<p> 
<img src="http://placehold.it/600x300" alt="Image from Placehold.it" height="300" width="600" class="vertical-rhythm"> 
Lorem ipsum dolar sit amet... 

Tip

It's a good idea to add height and width attributes to all of your images anyways. It helps with page performance, SEO, and accessibility.

We could be lazy and just do this for desktop, but that's not realistic. In the real world, we're going to need to make this responsive.

In our screen.scss file, place the following rule:

// mastering-sass/ch03/scss/screen.scss 
.vertical-rhythm[height="300"][width="600"] { 
    height: rhythm(6); 
    width: auto; // important to maintain the aspect ratio 
    display: block; // Make sure text starts on its own line 
} 

If you're not too familiar with using attribute selectors, what we're saying is "for each element with a class of vertical-rhythm and a height attribute equaling 300 and width attribute equaling 600 add these styles."

The function we're using tells Compass we want this elements height to be 6 lines of vertical rhythm height, basically our line-height * 6.

A few things you need to know

The first thing you'll need to know is that you could potentially have a media query every 50 - 100px to properly set heights for every few lines of our vertical rhythm. We're going to increase our rhythm by 2 at increments of around every 100px. Therefore, our next breakpoint will be around 420px. We'll write that media query in a moment.

The next thing you need to know is using CSS (even with Compass and Sass) to give images a vertical rhythm, while very possible, is quite a challenge and very time consuming on large, complex websites. Each image (or any element for that matter) of different aspect ratios (height/width) will require individual attention. This is really important, and also the reason why I wouldn't recommend using CSS to give images height for vertical rhythm. There's simply too many possibilities, and too much time needed to handle it for each image on each screen size and all the possible aspect ratios.

Also, what happens when you have a column-based grid layout? Your image will need to stay within a column with padding and on numerous screen sizes. To do this with CSS will result in numerous media queries that would depend entirely on your HTML structure to work. This is a bad idea for many reasons. It leads to very tightly coupled markup and styles, or a lot of presentational classes. We'll cover why both of those are bad in later chapters, but for now just know it's not really a realistic idea beyond very simple designs.

For that reason, setting vertical rhythm on images is the perfect candidate for some JavaScript to handle the calculations in a way that doesn't require any additional CSS or classes.

Note

I've actually written a small jQuery plugin called Rhythmic that does exactly that. You can find it at https://GitHub.com/lukewatts/rhythmic.

Lastly, these problems aren't only with images. You'll find other elements will often break your vertical rhythm, such as videos, embedded content, and advertisements.

Basically, vertical rhythm is hard, even with tools such as Compass to ease the way. With all that said, let's continue getting this page looking right. I'll leave it up to you to decide if you think vertical rhythm is something you want to use yourself.

Breakpoints and media queries

I can already feel many readers cringe at the thought of writing media queries for every 100px. A breakpoint for 420px, 520px, and 620px?! Many of you will have a very strict set of numbers you associate with breakpoints and media queries. Generally, these are 320px, 768px, 960px, 1024px, 1140px, 1280px, and any combination of these.

I was the same for a long time. I strived to fit my content into the most common device sizes or popular framework conventions. This include device orientation such as portrait and landscape. However, more often than not we shouldn't aim to fit the device. The device shouldn't be our prime concern, the content should. In this case we're not worried about how our image looks at 768px. We're worried about when we need it to grow to fit our content and our vertical rhythm the best. That just happens to be about 420px. So our next rule in screen.scss will be as follows:

// mastering-sass/ch03/scss/screen.scss 
.vertical-rhythm[height="300"][width="600"] { 
    height: rhythm(6); 
    width: auto; 
    display: block;     
     
 @media (min-width: 420px) { 
 height: rhythm(8); 
 width: auto; 
 display: block; 
 } 
} 

Now, we've used width: auto and display: block once already, and they're going to be required for all of our vertical-rhythm classes, so let's move it in its own rule so we don't need to keep repeating it.

Just above our first vertical-rhythm rule, add the following:

// mastering-sass/ch03/scss/screen.scss  
.vertical-rhythm { 
 display: block; 
 width: auto; 
} 
 
.vertical-rhythm[height="300"][width="600"] { 
    height: rhythm(6); 
 
    @media (min-width: 420px) { 
        height: rhythm(8); 
    } 
} 

For brevity's sake, I'm going to add the rest of our media queries together here. That way we can move on to the other image and also giving our headings correct sizes:

// mastering-sass/ch03/scss/screen.scss 
.vertical-rhythm[height="300"][width="600"] { 
    height: rhythm(6); 
 
    @media (min-width: 420px) { 
        height: rhythm(8); 
    } 
 
    @media (min-width: 520px) { 
        height: rhythm(10); 
    } 
 
    @media (min-width: 620px) { 
        height: rhythm(12); 
    } 
} 

I think I can safely assume you understand the process for the next image. This also clarifies why we need to use our height and width attributes to target images correctly. Inside index.html, add the height and width attributes to the second image and add the class of vertical-rhythm:

// mastering-sass/ch03/index.html 
<p> 
<img src="http://placehold.it/300x200" alt="Image from Placehold.it" style="float:left;" height="300" width="200" class="vertical-rhythm"> 
Lorem ipsum dolar sit amet... 

Fortunately, our images maximum width is 300, so we don't need to add any media queries. This one rule will do:

// mastering-sass/ch03/scss/screen.scss 
.vertical-rhythm[height="200"][width="300"] { 
    height: rhythm(8); 
} 

Aspect ratio

This is where the aspect ratio and the dimensions of the image are important. For an image with an original width of 300px and height of 200px, our new height will be rhythm(8), or 12em. However, an image of 300px width and 500px height requires its own calculations. This means to write CSS that deals with all possible image proportions is simply not realistic. So I want to stress that you should look at a JavaScript alternative instead of using CSS for vertical rhythm on elements such as images, video, and embedded material.