Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?

In defence of pixel values in media queries

I'll show you how deep the rabbit hole goes.

This is a guest post by Andrey Mikhaylov aka lolmaus, a web developer from Moscow. Follow him on Twitter: @lolmaus_en. Passing the word to Andrey now:

When reading frontend-related articles on the web, you regularly stumble upon a recommendation not to use pixel values in media queries. Here's a recent example from Brad, the host of this blog. Let me cite the relevant passage:

Firstly, we’re already ditching pixels in favor of ems, rems and percentages in every other aspect of our styles, so why not carry that through to our media query values? Secondly, authoring media queries in relative units allows browsers to adjust the design based on the user zoom level, resulting in a more pleasant, more accessible reading experience.

What if i told you that not only pixel values in media queries aren't bad, but they're actually superior to ems in certain cases?


1. Pixel values do not prevent media queries from being applied during zoom

The statement that pixel-based media queries do not work when zooming in the page is simply false. They work fine in all browsers that adjust page width when zooming. This includes all modern browsers (with a sorry exception for Safari which doesn't implement this kind of zoom at all).

Even Internet Explorer 8 does that fine. Wait, IE8 does not support media queries! Well, with px-based media queries you can use Respond.js, and media queries will be applied correctly while zooming. You hold the Ctrl key, scroll the mouse wheel, and the page layout is being readjusted.

On the website shown on the animation i used CSS like that:

@media (min-width: 401px) {
  #header-first {
    float: left;
    width: 47.82609%;
    margin-right: 4.34783%; }}

I don't have a more ancient IE at hand to test, but it might work in IE 6 and 7 as well. Which should not matter anyway because their share is finally very low. In mother Russia for instance it's 0.7% for IE7 and 0.1% for IE6, and mostly due to government institutions. Their world share appears more considerable, but mostly due to China. Clicky reports ~1.8% for IE 7 in US.

So, let's set it straight. The problem which is said to be the main reason for not using pixels in media queries does not exist. Apparently, it's a myth, probably originating from the fact that in ancient times pixel values prevented fonts from zooming properly. This myth is passed on and on, regularly appearing in blogs of frontend gurus and publications of influential websites, and nobody has bothered to actually try it.

The discrimination of pixels for defining sizes of fonts and boxes is another interesting statement that should be challenged. The official Github CSS style guide for instance recommends using px for font sizes, because it offers absolute control over text. But this is a topic for another article.

2. Changing base font size shifts em-based breakpoints

Imagine the following situation. Your boss or your client calls you and says that the font size on his website is too small for his wife to read comfortably. He insists you should enlarge it despite your objections. So you cast a hangdog look at the door of your UX department, open the CSS code and change the base font size from 13px to 16px (yes, the base font size is always set in pixels).

What happens next? You find all your em breakpoints shift. Now on a tablet you see a mobile layout, and it looks terrible (please, open the link and set the window a bit less than 900px wide). Is that what you wanted? Hardly. I bet that you'll find yourself adjusting all your media queries hastily, swearing out loud if your project doesn't use a preprocessor.

Yes, i'm aware of the Content First approach which states that breakpoints should shift proportional to content's width. This makes the content equally comfortable to consume on any screen width and saves you from setting individual media queries for a kajillion of devices.

But don't lie to yourself. Almost in any project you want (or your client wants) a certain layout for each device type. For example, you want a column of thumbnails appear as a grid of three on tablets. Do you want your grid appear as a single column of enormous thumbnails when you adjust the base font size? No.

Or maybe your designer drew a sidebar that should appear on tablets in landscape. It should be there regardless of base font size. You'd rather fix the sidebars font size than have it disappear when base font size is changed.

Of course, you should take care that the line length of the main text does not become uncomfortably large or small. But the matter is that the comfortable line length is a very speculative value. You can hear that it should be 45—75 characters wide, or 12 words wide, or whatever. But glossy magazines use 3-word lines far and wide, and nobody bats an eye. On the other hand, many large websites use lines longer than recommended. For example, Smashing Magazine has a limit of ~100 characters, Time has ~130.

3. Adjacent em-based media queries overlap

Consider this example:

.container {
  color: black;
  background-color: white; }}

@media (max-width: 40em) {
  .container { color: red; }}

@media (min-width: 40em) {
  .container { background-color: red; }}

What will a visitor see if he's “lucky” to have browser width of exaclty 40em?

The width of the overlap is only one pixel, but it exists and it will keep ruining your site's look and layout for random visitors.

With pixels this problem is solved trivially and absolutely reliably:

@media (max-width: 600px) { /* ... */ }
@media (min-width: 601px) { /* ... */ }

When i discovered the overlap, i've been blindly following the myth and tried to find a solution for ems. At first i tried using a fraction of an em: (min-width: 20.1em). Instead of an overlap, this created a gap: at certain width neither of media queries was applied. Then i tried, 20.01em, 20.001em... by using what Russians call “artillery fork method”, i managed to find the correct remainder value.

But then i realised that the correct remainder is different for every font size. Being a SASS enthusiast, i started coding a function that would accept an em breakpoint and a font size, multiply them, add 1, and then divide the result by the font size. Piece of cake, huh?

I've planned that at this point you should feel some vague discomfort. A slight feeling that i'm leading you by a wrong path. At least that was what i felt when was coding the function. I asked myself: man, what am i actually doing here?

And the answer is that...

4. Ems in media queries are merely a middleman between two pixel values: base font size and browser window width

As i mentioned earlier, base font size is always set in pixels. Otherwise browsers wouldn't know how to map the font size to screen pixels. If you don't provide a pixel value, then browsers will use the default value of 16px and multiply it by your relative value if you provided it.

Min-width and max-width media queries are compared against the browser window width, which is always a whole number of pixels.

So when you define your breakpoints in ems, you firstly have to calculate them from pixels and then you have to convert them back to pixels whenever you compare them to window widths. You do it all the time, otherwise you just don't know at what width your layout actually breaks.

Why bother? Just use pixels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment