If you’re interested in adding retina image support to your website or app and you happen to be using SCSS, here’s a handy shortcut that makes it dead simple.
Just include this SCSS mixin in any rule and specify the high resolution image’s path and device independent pixel dimensions. Here’s an example:
div.logo {
background: url("logo.png") no-repeat;
@include image-2x("logo2x.png", 100px, 25px);
}
Putting the high resolution alternative in the same rule as the normal image instead of putting it in a separate @media query rule or in different stylesheet altogether is a big win in terms of clarity in our CSS. It’s easier to read, easier to understand and easier to maintain.
The image-2x mixin detects high resolution displays like this:
@mixin image-2x($image, $width, $height) {
@media (min--moz-device-pixel-ratio: 1.3),
(-o-min-device-pixel-ratio: 2.6/2),
(-webkit-min-device-pixel-ratio: 1.3),
(min-device-pixel-ratio: 1.3),
(min-resolution: 1.3dppx) {
/* on retina, use image that's scaled by 2 */
background-image: url($image);
background-size: $width $height;
}
}
The mixin not only makes development easier, but it centralizes the definition of high resolution displays so it can easily be changed globally as more devices come to market. The @media query is based on the one in Thomas Fuchs’ Retinafy book but, for example, we’ve already modified it to define the Google Nexus 7 with it’s 1.3 pixel ratio as a retina-capable device.
A key insight here is that with SCSS, @media queries can be nested inside other rules. Such that these both work the same:
@media print {
body {
// print styles
}
}
body {
@media print {
// print styles
}
}
Purists of hand-crafted CSS may rail that this method results in the rule being repeated in the compiled CSS each time we use this mixin and that’s true. Basecamp is light on images so we’re talking about a handful of repetitions, not dozens or hundreds. It also seems likely that as SCSS continues to improve, these rules will be smartly combined. For now that trade-off is worth the improved clarity and convenience in our code.
Aaron Jensen
on 11 Oct 12You can get media query combining right now w/ sprockets using https://github.com/aaronjensen/sprockets-media_query_combiner
Brandon
on 11 Oct 12I created a Gist for lazy LESS CSS version of this awesome mixin! https://gist.github.com/3874012
Richard Lyon
on 11 Oct 12You can get the combination fairly easily by having the initial mixin simply append to a list (selector + image) and have a final mixin which spits out a combined list.
This does, however, cause the issue of your cascade breaking.. but that will happen anyway if #116 gets implemented.
River
on 11 Oct 12Even better, if you’re using Compass, you can automatically add dimensions to your mixin.
Compass image dimensions helpers
Even better than that, though, is you could just feed it the image names and have it handle everything else.
2X Mixin
If you wanted to get very fancy you could write a function to take one image name, parse it, and generate the 2x image name automagically. That way, you’d only ever need to pass one image name into the mixin.
mezza
on 11 Oct 12V cool
Phil Ricketts
on 11 Oct 12Works great.
Modified above gist work: https://gist.github.com/3874841
ali
on 11 Oct 12Another solution for Compass users is this helper and mixin which automatically applies the retina CSS if a file is found with a ’@2x’ suffix. It also takes advantage of the image-width helpers that the above comment mentions.
http://blog.joelambert.co.uk/2012/03/09/compass-sass-mixins-for-simple-retina-images-on-websites/
Mark
on 12 Oct 12I find the scaled down versions of the images work well enough so I just use the 2x versions by default and combine them all in a sprite, even for non-retina.
You only need to fall back to 1x for browsers that don’t support background-size (ie)
https://gist.github.com/3877549
ADI
on 12 Oct 12Great post, you should do more on coding.
James
on 13 Oct 12Slightly off topic, but what IDE is that? I’m really loving that color scheme on the text.
Johnny
on 14 Oct 12I’ve just found this on your blog: http://37signals.com/svn/posts/93-its-the-content-not-the-icons
Funnily enough, nowadays you have the “tweet” and “like” buttons on your blog. How does it hold with the post mentioned above?
Fadi E.
on 14 Oct 12Hi Jason,
I wonder whether that code in the CSS is actually valid CSS.
The way I would do it is I would a condition in the PHP code to include that CSS (instead of doing it across the board).
website design bangalore
on 15 Oct 12A critical thing to remember is that this can become very inefficient if you are using it in many places, as sass’s implementation currently just pulls the media query repeatedly out of the current selector, rather than looking through and combining media queries into blocks for each resolution.
Janmejai
on 17 Oct 12thanks,helped me a lot.
George Morris
on 17 Oct 12Exactly why we created RetinaJS – http://retinajs.com
Boris Kaiser
on 17 Oct 12And here’s my solution with Compass: https://gist.github.com/3908158
This discussion is closed.