Maintain vertical rhythm with CSS and jQuery

  • Knowledge needed: CSS, basic jQuery
  • Requires: jQuery, CSS, HTML
  • Project time: 30 minutes
  • Download source files

Assuming you design from the content out, the first decision to effect your design has to be type related. Even by not choosing a typeface you’ve done something that impacts your site. Type is core to print and web design, and it’s complex; there are a lot of accumulated terms, practices, rules, and techniques that go into its good use. This article is concerned with one technique for managing one aspect of type, one that’s been hard to do online but is routine in print: maintaining a consistent vertical rhythm, which in turn allows us to achieve a professional layout.

Laying out type

In print, for any item with a sizeable amount of text, the foundation of the design is likely to be a baseline-grid. It’s used to bring structure to the page and guides the vertical flow of content. Almost everything is placed with respect to that baseline grid. Don’t worry if you don’t recognise the terms, no-one is unfamiliar with baselines or baseline grids; you already know about them. Think back to school, when you undoubtedly wrote on lined paper – as you wrote you placed the bottom of your letters neatly onto each of the lines on the paper. The baseline and baseline grid in action. The baseline is an imaginary line onto which the bottom of letters align. If you look at this article now, you’ll “see” a baseline, even though there isn’t really a line. Your brain puts one there for you, it’s why you can read sentences. The lines on lined paper? They’re a baseline grid. Straight so your sentences are straight, and set at regular intervals so your text has a regular vertical rhythm.

Vertical rhythm

Vertical rhythm dictates where on the page text is located. It is one component that effects our ability to scan and read blocks of text, and it helps inform our emotional responses. When text has a strong vertical rhythm and good spacing we feel it is professional, considered, authoritative, and comfortable to read. When text has poor rhythm and spacing we feel it is less considered, less professional, and often harder to read. Vertical rhythm is one part usability and one part aesthetics.

Conducting the rhythm

Unfortunately the web is still the poor cousin of print in terms of its ability to enact some fundamental practices regarding type. On the web we can’t use a baseline grid in the same way a print designer (or child at school) does – we can’t align the text’s baseline to a document’s baseline grid. CSS has no concept of a baseline grid. So, our text won't sit exactly on the lines of a baseline grid. Instead, it will be centred vertically in the gap between the lines. It’s the best the web can do.

Let's get practical with an example document. Firstly, we’ll set the beat by making a visible baseline grid. To do this we’ll use a repeating background image to draw regular horizontal lines 22px apart:

  1. html { background: #fff url(baseline_22.png); }

Hurrah, we have our lined paper!

You will note that nothing lines up. To make everything line up we want the bottom edge of all elements to hit one of those lines. The easiest way to do that is make sure all elements take up a vertical height (including margins) that is a multiple of 22. Here’s some CSS that does just that. I’m using the REM unit, but giving an EM fallback for browsers that don’t understand REM. I’m also including the PX unit equivalent in comments. If you don’t yet understand REM/EM then you could just use the px values instead – they’re all equivalent:

  1. html { /* font-size: 16px, line-height: 22px */
  2. font: 100%/1.375 "Helvetica Neue", Helvetica, Arial, sans-serif;
  3. background: #fff url(baseline_22.png); }
  4. h1, h2, h3, h4, h5, h6 { /* margin-top and bottom are both 22px */
  5. /* em fallback */ margin: 1.375em 0;
  6. margin: 1.375rem 0; }
  7. h1 { /* font-size is 32px, line-height is 44px */
  8. /* em fallback */ font-size: 2em;
  9. font-size: 2rem; line-height: 1.375; }
  10. h2 { /* font-size is 26px, line-height is 44px */
  11. /* em fallback */ font-size: 1.75em;
  12. font-size: 1.75rem; line-height: 1.5714285714; }
  13. h3, h4, h5, h6 { /* font-size is 22px, line-height is 22px */
  14. /* em fallback */ font-size: 1.375em;
  15. font-size: 1.375rem; line-height : 1; }
  16. p, ul, blockquote { /* bottom margin is 22px, line-height is inherited from html (22px) */
  17. /* em fallback */ margin-top: 0; margin-bottom: 1.375em;
  18. margin-top: 0; margin-bottom: 1.375rem; }

Let’s take a look at what that gives us. Notice how all of the text aligns nicely? It doesn’t sit on the baseline, but it does have a predictable vertical rhythm. It’s nice and tidy.

Dealing with images

Images make things more complicated. Take a look what happens to our rhythm when we include some. They disrupt it like a skip in a record – the tempo is right but the timing is off. The alignment becomes shifted. It’s because images are unlikely to have a height that’s a multiple of the baseline, so the bottom edge doesn’t line up with our baseline grid.

To fix it all we really need to do is add a margin to each image, making the bottom of the margin line up with our grid. Which is simple enough to automate with a little JavaScript. Here’s our basic plan:

  1. Figure out the height of each image.
  2. See how many times the baseline value divides into the vertical space the image currently takes up, and get the remainder.
  3. Subtract the remainder from the baseline to give the offset we need to apply on the image.
  4. Apply the offset as a margin to the bottom of the image.

The bottom of the image’s vertical space would now align correctly with the baseline grid. Here’s a basic function in jQuery that does this:

  1. $(window).bind('load', function(){
  2. $("img").each(function() {
  3. /* variables */
  4. var this_img = $(this);
  5. var baseline = 22;
  6. var img_height = this_img.height();
  7. /* do the maths */
  8. var remainder = parseFloat(img_height%baseline);
  9. /* how much do we need to add? */
  10. var offset = parseFloat(baseline-remainder);
  11. /* apply the margin to the image */
  12. this_img.css("margin-bottom",offset+"px");
  13. });
  14. });

Why the window.bind line? Because we have to wait until the images are loaded before we can reliably get their sizes. Here’s an example with this basic code running.

Improving the jQuery

The world is rarely straight-forward, and so it turns out here – we have to deal with quite a few implementation details. What’s wrong with the function we have? Plenty:

  • It produces nasty results with images that are inline rather than floated or block.
  • It seems buggy on some images, specifically the ones in containers.
  • It doesn’t deal with liquid layouts.
  • It’s not very re-usable.

We don’t want to apply this behaviour to images that are inline, like the smiley face in the example. Inline images are aligned so the bottom edge sits on the same baseline as the text (not the baseline grid). That means the image is offset vertically. Neither CSS nor JS give us a way to find out where the baseline for a text element is, so we don’t know the offset. We must ignore inline images, and apply our fix only to images that are set to display:block (fortunately, any floated image is automatically set to display block).

If an image is in a container the margin applied to the image may be hidden because of overflow settings on the container. Also, we may not want the margin on the image, but on the container element instead. In the example, we’d rather have margins on the white box than on the image inside the box, so we can avoid getting weird gaps that appear in the box.

The function only runs once, but on a liquid design the images change height when the browser is re-sized (try resizing the example to something quite narrow to see this). Resizing breaks the rhythm again. We need the function to run after the browser’s been resized as well as after page load. Liquid layouts also introduce other problems; images can be fractional pixels high, for example 132.34px. That in turn can cause unexpected results, even if we apply a fractional margin (if you’re interested, here’s why: So, we’re going to need to massage the image into a whole pixel height to avoid layout bugs caused by fractional pixels.

Lastly, we should make this into a more re-usable function. In fact, with the complexity a practical solution needs over the theoretical solution, we should make a plug-in that can be re-used in other projects.

In the last example you’ll find the code that achieves all of this. The plug-in JavaScript is heavily commented so you can follow along. You can use the plug-in by calling it as follows:

  1. $(window).bind('load', function(){
  2. $("img").baselineAlign();
  3. });

Or, you can tell the plug-in to apply the margin to a named container, if one exists as a parent of the image:

  1. $(window).bind('load', function(){
  2. $("img").baselineAlign({container:'.popup'});
  3. });


Keeping a good vertical rhythm is a subtle but effective design practice used regularly in print. You now know the basic principles, have a working knowledge of baselines and the baseline grid, and know some of the limitations of CSS text layout versus print. You also know how to work around those limitations, compose your documents to any vertical rhythm you like, and you have a tool to help deal with disruptive image content.

As CSS matures we continue to get more features in-line with our print cousins, so a good understanding of type will become more important for creating quality websites. If you’d like to learn more about type in general I highly recommend (and buying the book to go with it). If you’re after CSS articles about type treatment there are numerous articles both here and elsewhere on the web. I’d also recommend catching up on the latest from Mark Boulton and Elliot Jay Stocks, both of whom talk often about type in relation to web design specifically.

Have fun!