Don't Use Em for Media Queries

In March 2016, Zell Liew published a really great in-depth post titled "PX, EM, or REM Media Queries?", where he shared detailed tests he had performed to figure out which unit was the best choice for media queries and ultimately recommended em units.

I've always used pixels for media queries, so although I was pretty convinced I should switch after reading Zell's post, I wanted to do a bit of testing on my own to make sure I really understood the problems with pixels before I renounced them forever.

The Problem

The problem Zell discovered in his tests is that when you zoom in on Safari, px media queries and em media queries trigger at different sizes.

Here I've got two containers set to change their background color at 400px and 25em respectively, with the zoom set to normal (100%):

In this example you can see that the backgrounds change at the same time, because 25em at the default font size of 16px matches the 400px breakpoint.

In this example, I'm using the same containers and breakpoints, but Safari is zoomed to 150%:

Link to Fiddle (don't forget to zoom!)

Here it's clear that Safari is triggering the pixel breakpoint much sooner than it triggers the em breakpoint.

The Mistake

In Zell's post, he concluded that Safari was not scaling the pixel breakpoint as the user zooms, and that when using pixels, Safari was triggering the breakpoint too soon.

But let's measure when the actual breakpoints are triggered:

Interesting! Safari is triggering the 400px breakpoint at 600px when zoomed to 150% (the correct behavior) but it's triggering the 25em breakpoint at 900px, which makes no sense at all.

So it turns out that yes, there is a bug in Safari, but it's not with how it handles px media queries, it's with how it handles em media queries.

When zoomed in, Safari triggers em breakpoints much later than it should.

Practical Consequences

Imagine a tiled layout where the number of columns changes based on the viewport width.

Here's what it might look like at around 960px wide:

Here's what happens when I zoom in to 150% in Safari using pixel media queries:

The layout drops to two columns, like you'd see at 640px viewport size.

Now look what happens when I zoom in to 150% in Safari using em media queries:

We're seeing the single column layout, even though the text is rendering at exactly the same size as it was when zoomed in using pixel media queries!

Again, this is because Safari is triggering the breakpoint far too late when using em units.

For good measure, here's what things look like at 100% and 150% using both px and em units in Safari, Chrome, and Firefox:

One of these things is not like the other 🤔

Just Use Pixels

Pixels are the only unit that behave consistently across all commonly used browsers.

"But what if the user has changed their browser's default font size?"

The short answer is set an explicit root font size in pixels. It will override the user's custom default font size which is mildly annoying for the user, but it will force them to zoom instead which always behaves the way you want.

You can still get bitten by Safari's "never use font sizes smaller than _" setting if the user has it set to a high value, but that setting has the power the wreak havoc on your designs no matter what you do. I try not to stress about it too much.