Nested retina media queries with Sass
Since switching from LESS to Sass I’ve been excited to learn how Sass makes responsive web design easier with @content blocks and @media mixins.
During a recent project I was interested to know if these mixins could be combined and nested with retina based media queries (mq). Could a retina-based mq be nested within a pixel based one? Turns out the answer is yes!
Here’s the media query mixin:
@mixin mq($mq) {
@if $mq == 690 { @media (max-width: 690px) { @content; } }
@if $mq == 320 { @media (max-width: 320px) { @content; } }
@if $mq == retina {
@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min--moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {
@content;
}
}
}
And here’s the Scss for a logo image replacement. Note the retina mq is nested within the 690 media query:
#site-title a {
@include hide-text;
display: block;
background: url(img/icons/spigot-logo.png) center center no-repeat;
width: 250px;
height: 100px;
position: relative;
top:5px;
left: -13px;
@include mq(retina) {
background-image: url(img/icons/[email protected]);
background-size: 250px 100px;
}
@include mq(690) {
background: url(img/icons/spigot-logo-small.png) center center no-repeat;
width: 90px;
height: 125px;
top: -3px;
left: -6px;
@include mq(retina) {
background-image: url(img/icons/[email protected]);
background-size: 90px 125px;
}
}
After compiling the file I was pleasantly surprised that the code not only worked, but output the final css in a pleasant manner, combining the @media logic into a single query:
@media only screen and (max-width: 690px) and (-webkit-min-device-pixel-ratio: 2), only screen and (max-width: 690px) and (min--moz-device-pixel-ratio: 2), only screen and (max-width: 690px) and (-o-min-device-pixel-ratio: 2 / 1), only screen and (max-width: 690px) and (min-device-pixel-ratio: 2), only screen and (max-width: 690px) and (min-resolution: 192dpi), only screen and (max-width: 690px) and (min-resolution: 2dppx) {
#site-title a {
background-image: url(img/icons/[email protected]);
background-size: 90px 125px;
}
}
Update: A reader emailed me with the following comment:
Good article, but I don’t know why you would write all that code if you could just run the Retina image through ImageOptim and call it a day. I ran the Retina version of your logo (attached) through ImageOptim and it went from 13k to 5k. No loss in quality at all.
— Clint
— Clint
Clint makes a great point – delivering a 5k retina sized image to non retina screens is trivial, and saves the extra css code. I still believe the technique is worth while when delivering larger images.
Hello,
I think the function could be made more reusable by rewriting it to accept any size instead of only pre-defined ones.
I\’m new to sass so I hope I didn\’t make any mistake in the following rewrite of your function
@mixin mq($mq) {
@if $mq == retina {
@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min–moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {
@content;
}
} @else {
@media (max-width: $mqpx) { @content; }
}
}