Pragmatic, practical font sizing in CSS

One thing I’ve been thinking a lot about lately is how to build sites properly. Not what we have been told is proper, but what actually makes sense for us as developers. I recently spoke at The Digital Barn on exactly this; my talk—Breaking Good Habits—dealt with how we as developers need to solve problems not only for our users and clients, but for ourselves as well.

Nicole Sullivan has laid a lot of new foundations for us in her work on OOCSS and her ‘unconventional’ but absolutely spot-on approach to building websites. Gems like the media object have seriously changed how I build websites and, if you take the time to study it for yourself, I think it might just do the same for you as well.

Double-stranded heading hierarchy

Another absolutely stellar nugget of wisdom she’s given us is what I call double-stranded heading hierarchy. This is the practice of defining a class every time you define a heading in CSS.

For example, if—for whatever reason—we want our h2s in our sidebar to be the same size as a h1, and the h4s in our footer to be the same size as a h3, we might have had some code like this:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2>Lorem</h2>
</div>

<div class=footer>
  <h4>Lorem</h4>
</div>


h1,
.sub-content h2 { [font styles] }
h2 { [font styles] }
h3,
.footer h4 { [font styles] }
h4 { [font styles] }
h5 { [font styles] }
h6 { [font styles] }

But now we’d have:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2 class=h1>Lorem</h2>
</div>

<div class=footer>
  <h4 class=h3>Lorem</h4>
</div>


h1,.h1 { [font styles] }
h2,.h2 { [font styles] }
h3,.h3 { [font styles] }
h4,.h4 { [font styles] }
h5,.h5 { [font styles] }
h6,.h6 { [font styles] }

As you can see, the former is far more arbitrary and those lists of selectors can soon become unwieldy, especially over a larger project. By assigning a class along with each heading style we now have those styles attached to a very flexible selector that can be moved anywhere, rather than to a very specific and non-movable one.

Now, I’m not such a fan of the .hN notation, I much prefer a solution that I believe to have been suggested by Mr Jeremy Keith, and that is to use abstract classes made up of the first six letters of the Greek alphabet, thus:

h1,.alpha   { [font styles] }
h2,.beta    { [font styles] }
h3,.gamma   { [font styles] }
h4,.delta   { [font styles] }
h5,.epsilon { [font styles] }
h6,.zeta    { [font styles] }

Which now gives us:

<div class=content>
  <h1>Lorem</h1>
</div>

<div class=sub-content>
  <h2 class=alpha>Lorem</h2>
</div>

<div class=footer>
  <h4 class=gamma>Lorem</h4>
</div>

Neat, huh?

So now .alpha can carry the style information of a h1 wherever you wish; it doesn’t depend on location or a type of element. A double-stranded heading hierarchy; lovely.

Extending this?

Okay, so now we have our heading styles all nice and portable we’ve won most of the battle. I’ve been using this method for months now and I love it. My CSS is so much more efficient, more portable, more powerful, I can build faster, I’m not repeating font styles over and over, but what next?

The other night whilst working on faavorite with Nick I came up with a full on font-sizing micro-framework.

The problems I found I had with font-sizing on any site include (but are not limited to):

  • Repetition of font-size, line-height etc declarations.
  • Overly-specific and/or location-dependent selectors (e.g. .sidebar h2 {}).
  • Arbitrary font sizes could and did creep into my CSS.
  • When using rem with px fallbacks, there is a lot to type!

And a few important things to remember:

  • Font sizes, like colour palettes, should be limited, preset and non-arbitrary.
  • Vertical rhythm is important and easy.
  • DRY code is important for both efficiency and maintainability.
  • It’s important to save yourself as much time as possible.
  • Classes are neither semantic or insemantic.

With this in mind, I decided that I wanted to use font-sizing much like a grid system; define it once in the stylesheet and just constantly reuse it.

Preset font sizes

Like colour palettes are, font sizes should be strict, predefined and intentional. From both a code and design point of view, you shouldn’t deviate from your scale—you shouldn’t really ever need to and doing so will just make code harder to work with.

Presetting your font sizes is pretty easy; typically you might have requirements for:

  • Normal body copy
  • Headings 1–6
  • Small print
  • A few other sizes for larger-than-normal headings etc.

Setting the base font size is simple, just pop it on the html and everything will inherit it, paragraphs, lists, tables, you name it.

For your headings you define a series of hN and its corresponding Greek letter class, e.g. h1, .alpha {}.

Non-standard font-sizing

You ever had that need to turn a design up to 11? When you have a masthead promo and even a h1 ain’t big enough? I think we all have…

It’s tempting to create a new, unique selector to cater for this new requirement, perhaps something like:

.masthead h1 { font-size:5em; }

And whilst this will work, you’ll only ever get that 5em goodness if you use specifically a h1 that is specifically in a .masthead. This isn’t very reusable at all. Sadface.

To combat this, I decided to create some new abstract classes, this time borrowing SI prefixes. Now we have the h1, .alpha {} through to h6, .zeta {} that we did before, but as well as those we have:

.giga { [font styles] }
.mega { [font styles] }
.kilo { [font styles] }

These classes are the ones above h1 and are the seldom used ones that make stuff massive!

Going the other way?

Okay, so far we’ve worked with body copy to headings to beyond; what about small print? Well I opted to use:

small,.omega.milli{ [font styles] }

small has been redefined in HTML5 so that’s an element we can use again freely and .omega is simply the last letter in the Greek alphabet.

Addendum

Tom Hudson suggested I use .milli for this as it goes below the regular scale. So, anything on the normal scale is Greek letters, anything off the scale (above or below) is SI prefixes.

Vertical rhythm

To maintain vertical rhythm we need two key ingredients; consistent line heights and consistent bottom margins. We need a magic number. This number is typically defined by the line height of your body copy, so if you have html { font-size:16px; line-height:1.5; } then your magic number is 16 x 1.5 = 24.

Now you know that all your line heights and margin bottoms have to be a multiple of 24px.

Bringing it together

It really is imperative to take a look at an actual example of all the above brought together in order to fully ‘get’ it. I made this jsFiddle demo of just CSS; you can add HTML and tinker with it yourselves, combining elements with classes to create double stranded, portable font sizing framework stuff!

Where does that leave us?

We now have a self-contained font-sizing framework which should hopefully mean we never need to define another font-size declaration again! We can manage our brand specific type rules from one place, we can build stuff faster, we can build faster stuff, we can keep our code DRYer, we can keep our styling a lot more consistent, we can keep styling location _in_dependent and we can make far reaching changes in one fell-swoop!

Feel free to take the code and modify or improve it.

Also please note that I am not suggesting we all use these specific classes; experiment, find your own, see what you’re comfortable with and report back!


Did you enjoy this? Hire me!

Hi there, I’m Harry. I am an award-winning Consultant Front-end Architect, designer, developer, writer and speaker from the UK. I write, tweet, speak and share code about authoring and scaling CSS for big websites. You can hire me.


I am currently accepting new projects for Q4, 2014 Referral scheme


Projects

  • inuitcss
  • ITCSS – coming soon…
  • CSS Guidelines

Events

  • Talk

    DaFED, Novi Sad (Serbia), November 2014

I am available for hire to consult, advise, and develop with passionate product teams across the globe.

I specialise in large, product-based projects where performance and CSS scalability and maintainability are paramount.