LESS baseline grid calculator

I have only been working with baseline grids for a little while, in fact this site is my first attempt at it, but aside from the fact that it's taken me a while to get my head around the general mathematics principles involved, the thing that I've found the most laborious about the process is all the calculations you need to do each time you're setting a different text size for an element.

Because it's not just the font-size, but also the line-height and margins and padding which have to be calculated, and if you're using ems instead of pixels, those calculations most of the time require a calculator. Using Alfred helps, but after a while I began to wish there was an easier way to do it. (Others are wondering whether it's worth bothering about at all, although the responses to that quickie poll seem to have stacked in favour of 'yes'.)

I'm not sure why it didn't occur to me before because I've been using LESS for a while now, but after looking at the Golden Grid System which also uses LESS, I realised I could use it to replace my calculator, and so I put together a mixin Github (also incidentally my first public repo) which you can see it in action on the demo page.

There's two mixins, one for plain text, headings, paragraphs and lists, and one for boxes.

@defaultfontsize: 16;
@defaultlineheight: @defaultfontsize*1.5;

.font(@fontsize:16,@lineheight:24,@multiplier:1,@lineheightreducer:1) {
	font-size: (@fontsize/@defaultfontsize)*1em;
	line-height: @lineheight/@fontsize/@lineheightreducer;
	margin: (@lineheight/@fontsize*(@multiplier/(@lineheight/@defaultlineheight)))*1em 0 0;
}

.boxes(@paddingtop:1,@paddingbottom:1,@bordertop:0,@borderbottom:0) {
	@border-top-width: @bordertop*1px;
	@border-bottom-width: @borderbottom*1px;
	padding-top: e(%("%sem%s", (((@paddingtop*@defaultlineheight)-@bordertop)/@defaultfontsize), `@{bordertop}>=1?'; border-top-width: @{border-top-width}':''` ));	
	padding-bottom: e(%("%sem%s", (((@paddingbottom*@defaultlineheight)-@borderbottom)/@defaultfontsize)*1, `@{borderbottom}>=1?'; border-bottom-width: @{border-bottom-width}':''` ));
}

Text

First, the mixin defines a couple of overall defaults which you can choose to suit whatever flavour of grid you want to set up. I'm using a line-height which is 1.5 times larger than the font-size which I've set at 16px, so in my case 16 × 1.5 = 24px.

After having established the defaults, you can then reset them for any particular element by passing in different values to the mixin.

@fontsize will be whatever font-size you want your text to be. @lineheight defaults to 24 and will change depending on the size of your text. Working out the required line-height should be the only calculation you have to do and it's an easy one as it will always be a multiple of your default line-height and should always be equal to or larger than your font-size. So if your font-size is 12, line-height will be 24; if your font-size is 24, it'll be 24; if your font-size is 36, line-height will be 48; if it's 50, it'll be 72, and so on.

@multiplier is used for larger text sizes if you want the margin to be larger than a standard 1 line-height's worth which is the default. In most cases, the only value other than 1 you would use would be 2 and only for large headings.

@lineheightreducer is used for text with a smaller font-size which won't look as good with such a large leading. Instead, use the reducer to bring it down to a more readable level. I've used 1.2 in the demo page which will mean five lines of smaller text will fit into the space of four lines of normal text. I would think you'd only need to use it for text sizes around 10px or 11px.

Boxes

@bordertop and @borderbottom default to 1px and the values that you pass in are pixel values.

@paddingtop and @paddingbottom also default to 1 but in this case 1 refers to the number of line spaces you want, so in this example, 24 pixels. Fractional values like .5 can be used too (see the demo page), but you can't use 0 because that would result in a negative padding value which is invalid CSS.

Originally I thought that because there's no way to display stuff conditionally using LESS, if you wanted a box with no borders a separate mixin would be needed with the border properties omitted. But apparently there is and credit for the last two lines of this mixin goes to Peter Wilson who not only wrote the code, but seems to have discovered this feature of LESS by himself (it's undocumented).

Code weight

One thing worth pointing out about the CSS generated by the .boxes mixin isn't particularly well optimised, e.g.

padding-top: 0.5625em; border-top-width: 3px;
padding-bottom: 0.5625em; border-bottom-width: 3px;
border-left-width: 3px;
border-right-width: 3px;

Not sure if there's any way around this to be honest. Possibly if you're concerned about the added code weight you could manually edit the CSS file that is output (if you're using the LESS app) or even paste the code back into your LESS file after you've used it to work out the padding em values. It's not ideal, but I guess it'll come down to how many rules you'd need to write using it.

Off the grid

I've used the formula Richard Rutter discusses in his 24 Ways article from a few years back, Compose to a Vertical Rhythm, and used this vertical rhythm tool to check that my calculations were coming out right.

One thing you'll notice on the demo page though is that while all the paragraphs line up nicely with the grid, most of the headings don't. Recently I came acrossThe Relevance of the Baseline Grid by Elliot Jay Stocks and in his example, all of the headings do sit nicely on the baseline grid although the example is for a printed layout and he's working with type at 7.5pt on 11pt. Which maybe wonder if maybe I'd gotten something wrong.

I've been trying to find a definitive answer as to which is correct, and it seems I'm not the only person to have come across the issue and wondered the same thing. In his article for Smashing Magazine,Technical Web Typography Guidelines and Techniques, Harry Roberts shows an example where the headings don't line up with the grid properly although the paragraphs do and he says:

You might think that something has gone wrong. But if you look, the paragraph lies just fine once you get back to the normal font size. To be honest, I’m not entirely sure about what causes this effect; the numbers we used are all correct, and the vertical rhythm as a whole remains intact, but individual lines of larger text appear to be offset from the baseline. I think this could be due, in part, to the glyphs’ setting in their em box.

And if you look at the example from Richard's vertical rhythm article, it too has headings that don't sit on the grid.

Likewise, text in the padded boxes also moves away from the grid although the tops and bottoms of the boxes themselves do not which means all the text that follows returns to its proper place again. Again, I'm a bit unsure about what the right thing to do here is. In the case of the boxes in the demo that just contain paragraphs and no headings, for the text to line up with the grid, the space between the edges of the box and the text would either have to be way too small or overly large.

I think it will likely come down to the situation in which the boxes are used. If it's for boxes that sit in the flow of other text, then I think the way I have it now is probably right, but if it was for full columns of text that were adjacent to other colums of non-boxed text, then you'd need to make some adjustments to get the boxed column to line up.

If anyone has any hints, suggestions, thoughts or ideas about this, I'd love to hear them in the comments.

Likewise, if you've got any suggestions about ways to improve the mixin, so go grab it now!