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/spigot-logo@2x.png); 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/spigot-logo-small@2x.png); 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/spigot-logo-small@2x.png); 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 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.
1 Comment
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; }
}
}