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. ems 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.
ems 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 pxmasquerading 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-sizeof each new context inrem. Often inline elements may warrant definingfont-sizeinembut normally block level elements don’t. When we’re creating a new context, we define thefont-sizeinrem. If it’s an object that will be used within various contexts, then useem. - Don’t define
width.width: autois 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 awidthdo it for a specific context and only within a@mediaquery, eg..homepage-feature .search-form { width: 50%; }. If your.search-form {}has no defined width, when you drop a.search-forminside your.sidebarwhich does have a width of30%, it will scale to fill that sidebar automatically. Brilliant. - Relative measurements are defined in
ems. This means they will be relative to the context they are dropped in. eg. My.search-formdoesn’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-heightetc. pxare allowed! Normally it’s the1pxvariety. eg.border: 1px solid. Often when you aren’t after1pxthough, 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 ems. 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.