All units are made equal, sort of
Over the past 10 years (I can’t believe it’s been that long either) I have read many articles claiming to have discovered the CSS unit to rule them all. The problem was, none of them did. They all sucked, in their own ways. As much as they were good at some things, they were poor in others.
##Roads past travelled
###px
The first unit I’d ever encountered in web development was the humble px
. It was very simple to understand (especially in a world where 1px
literally meant one pixel.) Living in the world of px
was very easy. We assumed that everyone used monitors that were 800x600 in size, later 1024x768 and so one. We had pixel-perfect control of our websites; we ruled the www with an iron fist — our way, or you don’t get to enter.
The drawbacks to the humble px
are clear today. Defining font-size
in px
is a bad idea; nowadays we care a little more for the consumers of our product and thus if they need bigger text we’d like them to be able to request their browser to make all the text a little bit bigger for them.
We also discovered that some people didn’t actually upgrade to 1024x768 computers, others had upgraded further to 1280x800 computers and then there actually existed a group of people who didn’t use their computer with all programs maximised all the time. px
weren’t flexible enough for us it seemed.
###%
For a while we stuck with px
as our unit of choice for font-size
but experimented with using %
for layout. width: 30%
for the sidebar, width: 68%
for the main content container. This worked great, sort of.
High resolutions viewed stretched websites. Low resolutions viewed squished websites. %
was not the unit to rule them all.
###em
I first heard about the em
when Richard Rutter wrote about them. It was connected to this idea of line-length and how text is easier for us to read when we limit the number of characters that span a line (it’s easier for us to find the start of the following line without losing our place.)
px
and %
units were out. em
s were in. But the problems of using the em
unit were soon very clear.
Layout-wise the em
was a glorified, scalable pixel. It suffered all the same failings of a px
based website; while at the same time making it impossible to understand what was actually going on in one’s CSS.
em
s were far too relative. It was impossible to tell that font-size: 1.333333em;
and font-size: 2.18888888em;
were in fact going to render at the same size. We had no way to reset the context of an element. Context inception occurred.
It was not right.
##A new road
The increased support of @media
queries, specifically of min-width
and max-width
, as well as the maturing of other parts of the CSS spec, specifically min-
/max-
height
/width
, has made it possible for us to combine all these units in one conversation. Allowing use to use the best of each unit and not deal with their shortcomings.
###rem
The final piece of the puzzle of course is the rem
unit. Think of it as an em
unit that is scoped to the html
element’s context.
html { font-size: 10px; }
p { font-size: 1.2rem; //12px }
html { font-size: 12px; }
p { font-size: 1.2rem; //14.4px }
I didn’t quite understand why this would be useful when I first read about this unit. To me, it was like a new px
masquerading as an em
which we all knew was better; despite being a pain in the ass to use.
The magic, however, is that, that definition is completely correct, and exactly why the unit is so awesome.
px
is a great unit because you completely understand what it means. px
is a unit scoped to the base unit of the resolution of your monitor (the super-context is the operating system). On HiDPI (Retina) displays this actually amounts to a 2x2 unit of actual pixels. But every element in your CSS file that references a px
is referencing a unit of the exact same size. 12px
is 12px
is 12px
. The reason why px
suck though, is that we have no control of that base unit. A px
is a px
is whatever our operating system decides a px
is.
With rem
: a rem
is a rem
is whatever we decided a rem
is in our html {}
block. We got to define the super-context of our units. 1.2rem
is always 1.2rem
and when we increase the size of 1rem
we increase the size of every 1.2rem
definition in exactly the same way. rem
units have a super-context of the html
element, instead of the operating system.
(This is useful when we want to bump up the size of everything for large viewports.)
We have stylesheet that we can actually understand. We have control over the relative size of every unit in our stylesheet. Clients (browsers, and thus the consumers of our products) also have control over the relative size of every rem
unit in our stylesheet. Assuming that you didn’t define it in px
of course.
##The rules of the new road
I now use the following rules when writing CSS.
- Define the super-context (
html
) font-size in%
,62.5%
if you want a general base font size of10px
. But don’t define it inpx
. - Define the
font-size
of each new context inrem
. Often inline elements may warrant definingfont-size
inem
but normally block level elements don’t. When we’re creating a new context, we define thefont-size
inrem
. If it’s an object that will be used within various contexts, then useem
. - Don’t define
width
.width: auto
is a blessing. It makes your CSS portable. It means you can define the classes for an “object” once, and drop it in anywhere and have it work. If you must define awidth
do it for a specific context and only within a@media
query, eg..homepage-feature .search-form { width: 50%; }
. If your.search-form {}
has no defined width, when you drop a.search-form
inside your.sidebar
which does have a width of30%
, it will scale to fill that sidebar automatically. Brilliant. - Relative measurements are defined in
em
s. This means they will be relative to the context they are dropped in. eg. My.search-form
doesn’t care aboutfont-size
, it hasn’t got one defined. When I drop it inside.homepage-feature { font-size: 2rem }
it will scale proportionally, just as it would if I dropped it in.sidebar { font-size: 1.2rem; }
. Relative measurements are usually vertical,height
,padding
,margin
,line-height
etc. px
are allowed! Normally it’s the1px
variety. eg.border: 1px solid
. Often when you aren’t after1px
though, you should be usingem
.
##Dealing with IE
There’s always this section, isn’t there. Unfortunately, IE exists and we must deal with it. IE 9 is the first version of IE that supports the rem
element. Fortunately, assuming you set your super-context to html { font-size: 62.5%; }
it is fairly simple to write backup CSS for IE-less-awesome.
* {
font-size: 10px;
font-size: 1rem;
}
Whenever you define a new context, you define it in pixels. You won’t need to touch your objects (eg. .search-form{}
) because they’re font-size is inherited or defined in em
s. Sure, you may protest that you lose the ability to change the font-size of your super-context now, but that’s only possible with media
query blocks and we know that the support for rem
units and @media
queries are almost identical. You can’t lose something you never had.