Yesterday, we had a discussion at work about rems, ems and percentages. I’ve used ems for media queries for years. I’ve used rems for font sizing for a couple of years. I felt like I had a pretty good handle on how it all works.
Most of you probably understand the difference, but let’s do a quick recap to refresh. When sizing using rem units, the sizing is based on the HTML element’s font size. When sizing using em units, the sizing is based on the parent element’s font size.
Here’s an em unit example: I’ve created a module named .foo and it contains several other elements. I want the heading inside to be 32px, so I set it to font-size: 2em. If my body font size is equal to 16px, and as long as I’ve set no font-size on the the .foo module or any ancestor of it, it will be rendered at 32px. However, if the .foo module or an ancestor has the font set to “font-size: 14px;” or “font-size: .875em;”, that new size (from the ancestor element) will now cascade to the heading inside as the base to compute by, and our 2em heading will be rendered at 28px.
This is the reason many of us moved to rem units. It’s more reliable to set the font-size on the html element and, if left at the 16px default, you can be confident that setting a heading size to 2rem will always give you a heading rendered at 32px. If you’re the only person writing the code in the site, you can get that same effect with em units by having a rule set in stone that you never, ever, ever set a font size on anything other than type (p, hx, lists, etc). But that’s in a perfect world where you control all the code and never pass it off to another developer. If you do work with other people, things can become messy and unreliable.
This brings me to the reason for this post — using em units for your media queries. Much has been written about it over the years, but the short story is — for reasons related to content and line-lengths — I use em units for my media queries so that the breakpoints adapt to changing font sizes. If the user changes their default,
or zooms the browser, all my breakpoints react to this new font-size base.
So what’s the big deal with the break points?
Based on yesterday’s conversation, I was doing an experiment. Since all my font-size, padding, margin, etc, is set in rem units, changing the size of the HTML element should scale the whole design either up or down. And it does. However, I expected it to also change the em-based breakpoints. It does not. I experimented with changing the size of the HTML element or the body element (sometimes even to straight up pixel values) and the breakpoints remained sized based on 16px. #headscratch (Here’s my Codepen to play with if you like: http://codepen.io/stefsullrew/pen/azRzOo)
After testing this several different ways, I did what one does — I reached out to the Twittersphere — the fount of all obscure knowledge. Within two minutes of posting, @susanjrobertson set me in the right direction: https://twitter.com/susanjrobertson/status/575378991017631744 I tested her theory, and by cracky, she was dead on! Fact is, the em base in media queries comes from the user’s setting (which is the 16px browser default if not changed by the user). The author has no control over this at all! Giving this some thought, it makes total sense. If my user has changed the default size of their browser to 32px because they have low vision, their line lengths will be shorter unless my media query breakpoints are now also using a 32px base and change accordingly.
The same applies to zooming in the browser, I want my media query breakpoints to change based on their zooming. (Lyza Danger, who likely wrote the article I read years ago that got me started with using em-based media queries has updated this week to state that browsers have fixed zooming.)
The moral of the story is — your media queries, sized with em units, are going to be based on 16px per em unit — unless the browser’s font size has been changed by the user. You can not override the user’s wishes. This means that the idea of scaling a whole design by changing the HTML element’s default size (maybe up to 18px, or down to 14px) will not change your media queries base size. It absolutely will scale your whole design to use any base size you desire (when all your values are rem based) — but your media queries will still be based on 16px. So in my opinion, it seems best to keep the HTML element at 100% (16px) so that it matches the em units of your media queries (or the overrides of your user).
12 Mar: Edited for clarity & to update with Lyza’s update!