Responsive Pixels
(Updated 19 Oct, 2014) Responsive pixels is a Stylus library that lets you think in pixels and deploy in rems with pixel fallbacks.
Em not impressed
Let me just come out and say it: ems are confusing.
In Ethan Marcotte's seminal Responsive Web Design book, for example, the font size of a link in a heading is set to 0.458333333333333em
.
Although Developer Me may stare puppy-eyed at all those pretty numbers, Designer Me has no blooming clue how to visualise the size of a font at 0.458333333333333em
.
And, even if I was a maths genius and possessed the visualisation skills of a 3D modelling application, I still couldn't tell you what a font looks like at 0.458333333333333em
because — to really mess with your mind — ems are relative units that are affected by the cascade. So that hideous number for the font size of a link in a heading is relative to whatever the font size of the heading is. Without knowing what the font size of the heading is, the font size of the link contained within it is meaningless to us when expressed in ems.
In the example in Ethan's book, an H1
element is 24 pixels tall in the original design. Instead of setting the font-size to 24 pixels, Ethan wants to express it in relative terms using ems. Expressing the size of an element in ems sizes it relative to the metrics of its parent or container element. Ethan calls this the context.
In this case, the element that contains the H1
tag is the body
which inherits the default font size of 16px from the root html
element.. In translating the pixel size of the heading to ems, we apply the target ÷ context = result formula (24px
÷ 16px
) to arrive at a relative and scalable font-size of 1.5em
.
OK, 1.5em
isn’t such a hard number. But it is infinitely harder to visualise than a simple pixel value like 24 pixels. I know somewhat intuitively what 24 pixels looks like but I’ll be darned if I can tell you what 1.5em looks like. And it gets worse as elements are nested within one another. The link in the heading in Ethan’s example is 11 pixels in the original design. To calculate its size relative to its parent, which is the H1
tag, you have to use the same target ÷ context = result formula, where target is 11 pixels, and the size of the H1
tag (the context) is 24 pixels. This gives you 11 ÷ 24 = 0.458333333333333em.
I'm sorry, but this is poppycock.
If something as basic as setting the dimensions of elements on a web page requires this much effort, our tools are broken and they must be fixed.
Even in Ethan’s book, he states: ‘I rely on my computer’s calculator program heavily, and simply pass the result into my CSS’. This is not a development process that is compatible with long-term sanity, people. If something is overly complicated, we must find a way to simplify it.
And, thankfully, there is a way to simplify this madness in CSS3 using rems.
Remember to breathe…
(The pun is strong with this one.)
A rem (short for root em) is a relative unit that gets its value from the font size of the root element (the html
element). So, if a margin was 16 pixels wide in your original design, for example, you would set the CSS property to 1rem
(since the default font size of the root html
element in browsers is 16px
). As rems are not affected by the cascade, they require an order of magnitude less cognitive load to use.
According to caniuse.com by Alexis Deveria, all current versions of major browsers, except Opera Mini, support sizing in rem units:
IE | Firefox | Chrome | Safari | Opera | iOS Safari | Opera Mini | Android | etc. |
---|---|---|---|---|---|---|---|---|
10.0: Supported | 19.0: Supported | 25.0: Supported | 6.0: Supported | 12.1: Supported | 6.0: Supported | 7.0: Not supported | 4.2: Supported | …: Supported |
But it’s not all moonlight and roses with rems.
You still need to do some maths.
Quick, now, given the default base font size of 16px
: what is the size of a 12 pixel margin in rems? Did you answer 0.75rem
? Of course you did, that was an easy one! 15px
? 0.9375rem
, of course. And, finally, a 18px
margin? Why, everyone knows that it can only be 1.125rem
.
It’s true that the numbers are less scary but that’s only part of the problem. Now I want you to visualise a box that’s 50 pixels by 50 pixels. Got it? That was actually rather easy wasn’t it?1 Now, visualise a box that is 3.125 rems by 3.125 rems. Not so easy, is it?
‘Because web design should not require a calculator.’
The real problem with these numbers is that we lose our ability to visualise designs in our heads as we work on them. And that’s a big problem, especially as we spend increasing amounts of time designing in the browser. Our inability to easily visualise the elements that we are styling can slow us down and discourage us from experimenting and tweaking our designs as much as we would otherwise.
As we lose the ability to visualise our designs — as we introduce an impedance mismatch between the values in our code and the values that we think with visually — we also encourage the artificial separation of the creative and technical aspects of our work. We perpetuate the myth that the technical side is hard and the sole domain of über geeks (‘oh, look at all those scary numbers, what do they all mean?’) and we perpetuate rights of passage (‘I had to learn this ridiculous poop, so should you’). Instead of glorifying rights of passage and overly‐complicated processes as a sort of geek merit badge, we should always be on the look out for ways to simplify things for everyone. Setting font sizes, margins, and padding in responsive designs should not require a degree in rocket science and it doesn’t help anyone if we make such basic foundations of web design and development unnecessarily complicated.
All this, of course, is a failing of our tools and workflows.
So, let’s fix that.
Responsive Pixels
We’ve seen how pixels are easy to work with and to visualise but, being absolute values, are harder to use in responsive designs. We’ve also seen that rems, being relative values, are better suited to responsive design and yet easier to understand and use than ems (as they are not affected by the cascade). If only we could use pixels when authoring our styles but have them behave like rems.
The great news is that we can. All we need to do is to make rems equivalent to pixels.
That is, make it so that 1 rem is equal to 1 pixel.
Or, in other words, make it so that 1 pixel is equal to 1 rem.2
Wouldn’t that be just amazing? Personally, I think it could usher in an era of peace and harmony that finally enables us to rid the world of disease and explore the far reaches of the galaxy in a spirit of mutual love and understanding the likes of which have not been see-
Right, so our lives would be easy as pie if 1 pixel was equal to 1 rem. We could put those pesky calculators away and get back to working with units (pixels) that we can easily visualise.
The easiest way to achieve this pixel parity with rems is to set the root font size of the HTML document to 1px
. In other words:
html
{
font-size: 1px;
}
This is basically what Chris Jacob suggests doing in his Elastic Pixels gist. And I started doing just that. And life was good. For a while.
Unfortunately, not all browsers let you set the root font size to 1px
. This is a bug, not a feature. On some browsers a 1px font size erroneously conflicts with the minimum font size setting in the accessibility settings (even if the actual computed font sizes of your elements are all larger than the minimum font size specified by the user). On Safari, for example, a root font size rule of 1px will be rewritten as 9px if the mininum font size in the user’s preferences is set to 9px. The effect will be to make everything on the page nine times bigger than intended. Additionally, some browsers — especially some console browsers (thank you, Anna Debenham, for letting me test with your toys) — appear to completely ignore any change to the root font size. Ah, browsers, ya gotta love ’em.
So, all this to say that we can’t just set the root font size to 1px
and be done with it. Bummer! However, (spoiler alert) there is hope.
CSS preprocessors to the rescue…
Since we cannot reliably change the root font size across browsers, the only thing left to do is to use a CSS preprocessor to do the maths for us.3
Using a CSS preprocessor and mixins, we can:
- Author using pixels,
- Have the pixel values converted automatically to rems
- Automatically keep the pixel values as fallbacks for older browsers.
Ah, CSS nirvana!
Here is an excerpt of one of the mixins I use in Stylus for setting font-size
in responsive pixels:
font-size unit(h, 'px')
font-size unit(h/16, 'rem')
As you can see, it does two things: firstly, it writes out the pixel value you originally supplied as the pixel fallback for compatibility with ancient browsers and then it writes out the rem‐based rule by dividing the pixel value by the root font size (16px
).
This means that you can pass 24px
as your margin, for example, knowing that the responsive pixels mixin will convert that for you to the correct number in rems (1.5rem
) and write the 24px
fallback for you. Your rem values are equivalent to your pixel values and you can visualise dimensions and spacing at a glance again.
So, responsive pixels enables you to use pixels while authoring and automatically translates them to rems with pixel fallback via CSS preprocessor mixins.
Scale all the things
So far so good, but what are the advantages? Well, since your pixels are responsive, you can scale things up or down by changing the root font size. If I want to make the font‐size smaller or larger at a breakpoint, for example, all I have to do is change the base font size. Since the responsive pixels mixins leave the base font size at 16px
, we have enough room to play before any browsers complain. And, when you do change the base font size, everything that you used responsive pixels for (margins, padding, etc.) will scale in proportion. That alone has the potential to save you from tweaking lots of different properties manually at breakpoints.
I was hesitant to publicise this until I had used it in a few real‐world projects in case any issues cropped up but I realised that I have been using the technique for about a year now and Laura and I have both used it in multiple projects and we’re both confident that it works. It makes our lives much easier by reducing our cognitive load so we can concentrate on, you know, actually designing and developing sites.
A real‐world example
Instead of a contrived example, take a look at the Ind.ie web site and the source code of the Stylus files we use there.
One important thing to note is that, while we don’t make use of it on the Ind.ie web site, you can easily scale the whole page up or down in proportion by changing the base font size. If used properly, this can greatly reduce the amount of manual tweaks you have to make at each breakpoint. e.g.,
@media only screen and (max-width: 480px)
html
font-size 14px
The other thing to note is that on the Ind.ie web site, nearly all of the values are proportional to a base unit. In this case, the base unit is the base line height and my properties are set to values like OneLineHeight
, TwoLineHeights
, ThreeQuartersLineHeight
, etc. Having a base unit makes it that much easier to achieve rhythm in the design.
Responsive Pixels Stylus Library
The way we use Responsive Pixels at Ind.ie is to add it to our projects as a Git submodule.
Clone the Responsive Pixels Stylus library from Ind.ie.
Usage
To use the Responsive Pixels Stylus Library:
- Import the responsive-pixels.styl library into your Stylus file.
- Use pixel values in your stylesheet rules.
- Compile your Stylus files into CSS.
One reason that I use Stylus instead of a different preprocessing library is that there is absolutely no overhead for mixins in Stylus. You can override a built‐in CSS property with a mixin by giving the mixin the exact same name as the built‐in property. So, for example, my responsive pixels mixin for font-size
is simply called font-size
.
And here’s some sample code:
@import responsive-pixels
body
font-size 24px
The Stylus code above will result in a font-size of 1.5rem
with a 24px
fallback rule in the final CSS:
body {
font-size: 24px;
font-size: 1.5rem;
}
Because web design should not require a calculator
And that’s it, really.
I’m not presenting Responsive Pixels as the way to do things, just as one possible way that works for us at Ind.ie and that we are using in all of our projects. Responsive Pixels is a technique and a tool that I hope will help you think and work visually when designing and developing responsive websites. It is not meant to entirely replace percentages or ems in your work as those units have specific use cases for which they are most suitable (e.g., layout for the former and reusable components for the latter). I find that using responsive pixels has made me enjoy making web sites again. I hope that you find it useful and I look forward to seeing Responsive Pixels libraries implemented in other CSS preprocessing languages soon.
Source
Footnotes
1 When it comes to visualisation, pixels are not ideal either, they’re just the best we have at the moment. For one thing, CSS pixels are logical pixels, not physical device pixels. So your 200px by 200px square is going to be roughly half the physical size on your iPad with its Retina screen. Pixels are easy to visualise when we know the resolution at which they will be displayed. Ideally, we would have actual physical units in CSS as they’re the easiest to visualise. If I ask you to visualise a 5cm by 5cm square you can do it immediately. 5cm is 5cm is 5cm… unless it’s 5cm in CSS, of course. Because in CSS, 5cm is not 5cm. Read Nick Sherman’s excellent article titled Responsive Typography is a Physical Discipline, But Your Computer Doesn’t Know It (Yet) for a good discussion of this topic. ↩
2 When I originally came up with this workflow, I called it Pixel‐Parity Rems and had the Stylus mixins on translate rems to pixels. While talking to Jeremy Keith about it over lunch, one day, he asked why I didn’t just author in pixels. It’s just a unit change but I agree that it makes more sense to use pixels as the original unit. Hence, I renamed Pixel‐Parity Rems to Responsive Pixels and updated the mixins. All this means is that you author using pixels as the unit and those values are automatically converted to Rems by the mixins (with pixel fallbacks, of course). ↩
3A big thank you to Laura Kalbag as seeing her work with pixel fallbacks for rems via mixins in SASS is what inspired the idea. ↩