Don't Use Em for Media Queries

...if you care about Safari 10 support.

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 10 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 10 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 10, Chrome, and Firefox:

One of these things is not like the other 🤔

The Good News

The good news is that this issue is fixed in Safari 11, and zooming while using em units for media queries now behaves like it does in every other browser.

At the time of this post, Safari 11 is at about 5.3% of global browser share and Safari 9/10 are at about 4.7%, so I bet within a year or so you won't have to worry about this issue.

In the mean time...

...use pixels for media queries. They 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.

Going Forward

Once Safari 10 is no longer commonly used, em units will be a good way to go for media queries as long as you're using relative units for everything else as well. They work properly with zooming, and also behave best with custom default font sizes.

That said, there's still nothing wrong with using pixels. In fact, if you're already setting a root font size in pixels, you should without a doubt be using pixels for your media queries too. They behave nicely in all browsers (as long as you set an explicit root font size) and are easier to reason about than em since device resolutions are measured in pixels as well.