All Articles

Effective Font Size Control

Are you having a hard time trying to control the size of your text using relative font sizes? Are you getting mad with the style-sheet you're working with as much as to define all font sizes in pixels? No, please, don't do it.

The temptation of using pixels units to fix font sizes is not a new tendency, but it is getting worst today because, well, we have now a good argument to release us from using relative font sizes, don't we? "Today browsers can zoom the page, not the text, so we're free to use pixels as font size units." Wrong. It is not up to us to decide how people will consult our pages, but it is up to us to do our best to give our readers all possible reading comfort. So, if our users prefer to zoom only the text, we shouldn't block him by fixing font sizes in pixels. At least, we can't do that just because we cannot manage to control font sizes in relative units.

The problem with relative font sizes is exactly because they're relative. When trying to adjust locally a font size, sometimes we simply don't get the expected result. The text is or too small or too big. Why does it happen? Well, mostly because our CSS has some basic, yet important flaws.

The biggest mistake we can make during our CSS design is to attribute font sizes to "non-textual" blocks.

From the CSS point of view, the HTML elements can be classified in two types: blocks and inlines. A block-level element is basically a container that will group other block or inline-level elements and, being a container, it has dimensions. Think of block-level elements as boxes.

Sometimes this box can hold any other element, like the div can, but sometimes our block-level element can contain only elements pertinent to its nature, like the <ul> element that can contain only <li> elements, for example.

An inline-element, on the other side, don't have dimensions and can only contain other inline elements like <strong>, <em>, <a>, etc. Think of inline-elements as text strings.

But, wait, that's not that simple. There are exceptions, of course. For example, the paragraph, the <p> tag. What is a paragraph? We can say that a paragraph is one or more sentences grouped in a logical way. You see? We're talking about sentences here, hence text, hence text strings. It means that it wouldn't be logical for a paragraph to hold other block elements. Would you put a box inside a string?

What I'm trying to show here is that, besides being of a block or inline level, an HTML element can be semantic or not, and there is where lies the core of our solution: we should define font sizes only for semantic block-level elements or "textual" blocks, if you prefer.

Logically, you would not say "this document is on 12pt", but "the text of this document is 12pt". So, why we would define font sizes for containers? Is it really logical? No, we must attribute sizes to text:

div.myblock {font-size: 0.9em;} /* WRONG */
div.myblock p {font-size: 0.9em;} /* YEAHH */

The golden rules

Rule number 1: Define your convertion rate

Browsers have, by default, the font size of reference set to 16px. That means that if you don't define any font size in your CSS, all your paragraphs, list items, definitions, etc. will be displayed at 16px.

When using "em" units we must first define the relation between one "em" unit and this font size of reference, and the more straightforward way is to make an even relation: 1em = 16px.

In order to do that, we'll simply declare for the body tag that its font size will be 100%:

body {font-size: 100%;}

Yes, the body element is a container, but in this case we're just fixing the convertion rate between "em" units and pixels. This convertion rate will allow us to easily foresee the size of our text. Attention, here is the only place where we will declare a font-size for a "non-textual" block-level element.

Rule number 2: Define default font-sizes for textual block-level elements (only)

Along with the definition of all default properties of our CSS, we'll define the default font size, in "em" units, only for the semantic block-level elements.

Those elements are:

  • <hX>
  • <p>
  • <li>
  • <dt>
  • <dd>
  • <th>
  • <td>

Have you notice? We'll not define a font size for a <ul> or for a <dl> because, although they're also semantic block elements, they'll not hold text directly, but they'll group elements who will.

If we define a font size in relative units to the semantic parent, let's say, the <ul>, we'll soon find ourselves having the same problem if we want to finetune the size of some text inside the <li>.

Rule number 3: Treat exceptions using percentage

We don't have problems to control the size of our text anymore. Cool! But what if we want to change the size of a inline-element contained by a textual block-level element?

Let's say that we want the text inside the <strong> tag to be not just bold text (as by default), but also a little bigger:

<div class="myblock">
  <p><strong>Be yourself; </strong> Everyone else is already taken.</p>
</div>

We know we're not suppose to « touch » inline-level elements, don't we? So, how can we change the size of this precise portion of text?

To use "em" units here would be a pitty because the level of control over the text size would be delicate, and under certain circumstances it can be tricky. So, if we want to be sure that all our font size system will stay robust and flexible during the lifetime of our CSS, we can simply use percentage to adjust the size of the text of inline-level elements:

div.myblock strong {font-size: 120%;}

The following declaration assures that this <strong> element will be 20% bigger than its direct, textual block-level father (the <p> element), and it will always be 20% bigger, no matter how we change the font-size of the later.