When it comes to specifying values, CSS provides a wide array of options to choose from. One of the most familiar, and probably easiest to work with, is pixels. These are known as absolute units. Other units, such as em and rem, are not absolute, but relative. The value of relative units changes, based on external factors; for example, the meaning of 2 em changes depending on which element (and sometimes even which property) you’re using it on. Naturally, this makes relative units more difficult to work with. The way the value of an em can change makes it seem unpredictable and less clear-cut than the pixel.
First, We’ll look into the unique value they bring to CSS, then I’ll help you make sense of them. I’ll explain how they work, and I’ll show you how to tame their seemingly unpredictable nature.
The power of relative values
In early computer application development (as well as in traditional publishing), developers (or publishers) knew the exact constraints of their medium. A particular program window might be 400 px wide by 300 px tall, or a page could be 4 in. wide by 6½ in. tall. Consequently, when developers set about laying out the application’s buttons and text, they knew exactly how big they could make those elements and exactly how much space that would leave them to work with for other items on the screen. On the web, this is not the case.
The struggle for pixel-perfect design
In the web environment, the user can have their browser window set to any number of sizes, and the CSS has to apply to it. Furthermore, users can resize the page after it’s opened, and the CSS needs to adjust to new constraints. This means that styles can’t be applied when you create your page; the browser must calculate those when the page is rendered onscreen. This adds a layer of abstraction to CSS. We can’t style an element according to an ideal context; we need to specify rules that’ll work in any context where that element could be placed. With today’s web, your page will need to render on a 4-in. phone screen as well as on a 30-in. monitor. For a long time, designers mitigated this complexity by focusing on “pixel-perfect” designs. They’d create a tightly defined container, often a centered column around 800 px wide. Then, within these constraints, they’d go about designing more or less like their predecessors did with native applications or print publications.
The end of the pixel-perfect web
When smartphones emerged, developers were forced to stop pretending everyone could have the same experience on their sites. Whether we loved it or hated it, we had to abandon columns of some known number of pixels, and begin thinking about responsive design. We could no longer hide from the abstraction that comes with CSS. We had to embrace it.
Relative units are one of the tools CSS provides to work at this level of abstraction. Instead of setting a font size at 14 px, you can set it to scale proportionally to the size of the window.
Ems and rems
Ems, the most common relative length unit, are a measure used in typography, referring to a specified font size. In CSS, 1 em means the font size of the current element; its exact value varies depending on the element you’re applying it to.
Example: Applying ems to padding.
.padded {
font-size: 16px;
padding: 1em; // sets padding to all side equal to 16px.
}
This padding has a specified value of 1em. This is multiplied by the font size, producing a rendered padding of 16 px.
Using ems can be convenient when setting properties like padding, height, width, or border-radius because these will scale evenly with the element if it inherits different font sizes, or if the user changes the font settings.
Here is another example
<!-- Size can be control via font -->
<!-- Will be small box -->
<span class="box box-small">Small</span>
<!-- Will be large box -->
<span class="box box-large">Large</span>
.box {
padding: 1em; /* depend on font size. */
border-radius: 1em; /* depend on font size */
background-color: lightgray;
}
.box-small {
font-size: 12px;
}
.box-large {
font-size: 18px;
}
Using ems to define font-size
When it comes to the font-size property, ems behave a little differently. ems are defined by the current element’s font size. But, if you declare font size: 1.2em, what does that mean? A font size can’t equal 1.2 times itself. Instead, font-size ems are derived from the inherited font size.
To determine the calculated pixel value, you’ll need to refer to the inherited font size of 16 px: 16 times 1.2 equals 19.2, so the calculated font size is 19.2 px. It’s helpful to know that, for most browsers, the default font size is 16 px. Technically, it’s the keyword value medium that calculates to 16 px.
THE SHRINKING FONT PROBLEM
Ems can produce unexpected results when you use them to specify the font sizes of multiple nested elements. To know the exact value for each element, you’ll need to know its inherited font size, which, if defined on the parent element in ems, requires you to know the parent element’s inherited size, and so on up the tree. This becomes quickly apparent when you use ems for the font size of lists and then nest lists several levels deep. The text is shrinking! This is exactly the sort of problem that leaves developers dreading the use of ems.
Correcting the shrinking text problem
ul {
font-size: .8em;
}
ul ul {
font-size: 1em;
}
This fixes the problem, though it’s not ideal; you’re setting a value and then immediately overriding it with another rule. It would be nicer if you could avoid overriding rules by inching up the specificity of the selectors. By now, it should be clear that ems can get away from you if you’re not careful. They’re nice for padding, margins, and element sizing, but when it comes to font size, they can get complicated. Thankfully, there is a better option—rems.
Using rems for font-size
Rem is short for root em. Instead of being relative to the current element, rems are relative to the root element. No matter where you apply it in the document, 1.2 rem has the same computed value: 1.2 times the font size of the root element. The following listing establishes the root font size and then uses rems to define the font size for unordered lists relative to that.
Specifying font size using rems
:root {
font-size: 1em;
}
ul {
font-size: .8rem;
}
In this example, the root font size is the browser’s default of 16 px (an em on the root element is relative to the browser’s default). Unordered lists have a specified font size of .8 rem, which calculates to 12.8 px. Because this is relative to the root, the font size will remain constant, even if you nest lists.
Rems simplify a lot of the complexities involved with ems. In fact, they offer a good middle ground between pixels and ems by providing the benefits of relative units, but are easier to work with. Does this mean you should use rems everywhere and abandon the other options? No.
In CSS, again, the answer is often, “it depends.” Rems are but one tool in your tool bag. An important part of mastering CSS is learning when to use which tool. My default is to use rems for font sizes, pixels for borders, and ems for most other measures, especially paddings, margins, and border radius (though I favor the use of percentages for container widths when necessary).
This way, font sizes are predictable, but you’ll still get the power of ems scaling your padding and margins, should other factors alter the font size of an element. Pixels make sense for borders, particularly when you want a nice fine line. These are my go-to units for the various properties, but again, they’re tools, and in some circumstances, a different tool does the job better.
When in doubt, use rems for font size, pixels for borders, and ems for most other properties.