Media Query & Asset Downloading Results

A little while back, I mentioned I was doing some research for the book about how images are downloaded when media queries are involved. To help with that, I wrote up some automated tests where Javascript could determine whether or not the image was requested and the results could be collected by Browserscope for review. I posted some initial findings, but I think I’ve got enough data now to be able to go into a bit more detail.

Test One: Image Tag

This page tried to hide an image contained within a div by using display: none. The HTML and CSS are below:

<div id="test1">
<img src="images/test1.png" alt="" />
</div>

@media all and (max-width: 600px) {
#test1 { display:none; }
}

The results

If there is one method of hiding images that I can say with 100% certainty should be avoided, it’s using display:none. It’s completely useless. It appears that Opera Mobile and Opera Mini don’t download the image (see the initial post for the reasons why), but the image is requested by, well, everyone else.

The results

Kudos to Jason Grigsby for catching this one. On the surface, it’s not entirely obvious why this would be any different than test two. However, when doing his initial research, he noticed this seemed to make a difference so he decided to test it. Lucky for us he did because this method is actually pretty reliable.

Tested

Requests Image

Android 2.1+

No

Blackberry (6.0+)

No

Chrome (16+)

No

Chrome Mobile

No

Fennec (10.0+)

Yes

Firefox (3.6+)

No

IE 9+

No

iOS (4.26+)

No

Kindle (3.0)

No

Opera (11.6+)

No

Opera Mini (6.5+)

No

Opera Mobile (11.5)

No

Safari (4+)

No

Conclusion

This method works well. With the exception of the over-eager Fennec, every tested browser only downloads the image when needed. The issue with this method is that you do have the requirement of being able to hide the containing element. If that’s an option, then feel free to go ahead and use this approach.

Test Four: Background Image with Cascade Override

In this test, a div is given a background image. If the screen is under 600px, then the div is given a different background image. This tested to see if both images were requested, or only the one needed. The HTML and CSS are below:

The results

While certainly better than using display:none, this method is a little spotty.

Tested

Requests Both

Android 2.1-3.0?

Yes

Android 4.0

No

Blackberry 6.0

Yes

Blackberry 7.0

No

Chrome (16+)

No

Chrome Mobile

No

Fennec (10.0+)

Yes

Firefox (3.6+)

No

IE 9+

No

iOS (4.26+)

No

Kindle (3.0)

Yes

Opera (11.6+)

No

Opera Mini (6.5+)

No

Opera Mobile (11.5)

No

Safari 4.0

Yes

Safari 5.0+

No

Conclusion

I’d avoid it. While the situation is improving, Android 2.x, which dominates the Android marketshare, still downloads both images as does Fennec and the Kindle. Between the three, but particularly because of Android, I would recommend looking at other options.

Conclusion

More browsers play along this time. Fennec, as always, just can’t control itself. Android 2.x is….odd. It requests both images, but only if the screen size is over 600px and the min-width media query kicks in. This behavior appears to stop as of Android 3. This is an odd one and I would love to know why the heck it happens. Actually, good news here. Jason Grigsby pinged me and said his results for this test weren’t jiving with what I reported here, so I re-ran the tests on a few Android 2.x devices. Turns out, my initial results were off: Android 2.x plays nicely and my initial runs of this test on that platform were wrong. Not only is this good news for developers, but it is also a much more sane behavior and it has restored my faith in humanity. Or at least my faith in Android.

It’s also worth nothing that if you use this method, you’ll need to consider alternate options for Internet Explorer 8 and under. Those versions of the browser don’t support media queries, so no image will be applied. Of course, this is simple enough to fix with conditional comments and an IE specific stylesheet.

Conclusion

I’m not going to spend much time on this, as it ended up being a throw away test. There were no differences in behavior between this and test two. The test was added because of a tweet where someone had mentioned they were getting different results than the original tests by Cloud Four, but the discrepancy ended up being caused by something else entirely (a typo, if I remember right).

Test Seven: Cascade Override for High Resolution

The final test was added to the suite a bit late. With the retina iPad around the corner, there were a lot of posts about how to handle serving images to high-res displays. In one post, Brad Frost mentioned he thought it would be interesting to see test results for this, so I added it in.

In this test, a div is given a background image. Then, by using the min-device-pixel-ratio meda query, a new background image was applied if the minimum ratio was 1.5.

The results

Of all the tests, this one is the one that could benefit the most from having some more people run it. That being said, it does look like the following behavior is accurate.

Tested

Requests Both

Android 2.1-3.0?

Yes

Android 4.0

No

Blackberry 6.0

No

Blackberry 7.0

No

Chrome (16+)

No

Chrome Mobile

No

Fennec (10.0+)

No

Firefox (3.6+)

No

IE 9+

No

iOS (4.26+)

No

Kindle (3.0)

No

Opera (11.6+)

No

Opera Mini (6.5+)

No

Opera Mobile (11.5)

No

Safari 4.0+

No

Conclusion

Again, this test could stand to be run a bit more, just to be safe. It looks like this method will work the vast majority of the time. Unfortunately, it appears Android 2.x will download both images if the device pixel ratio is above or equal to 1.5 (or whatever value you set in the media query). So in the case of the above tests, if you’ve got a high resolution device running Android 2.x you’re out of luck.

The good news, for now, is that I’m unaware of any Android device with a device pixel ratio over 1.5. So if you’re targeting the retina display iOS devices, you could set your min-device-pixel-ratio to 2 and be safe. And of course, now that I’ve said it, I fully expect the first 3 comments for this post to all correct me and point out the one Android device that just has to prove me wrong.

The earliest rounds of this test looked more promising for Android, so this is a bit of a bummer for me. They’re the only browser that seems to mess it up, but they’re also one of the biggest players.

Recommendations

If you’re going to hide a content image, you’re not going to be able to do it by setting display:none. I recommend using a Javascript or server-side based approach instead.

If you want to hide a background image, your best bet is to hide the parent element. If you can’t do that, then use a cascade override (like test five above) and set the background-image to none when you want it hidden.

For swapping background images, define them both inside of media queries.

Going Forward

If you run any of the tests and think something above is incorrect, either drop me a line or say report it on GitHub so I can dig into it. The same goes for adding any additional tests.