Multiple Background Images Using Sass and Media Queries

Multiple background images

I am trying to create a quick way to theme Kidblog.org’s class pages, and since the largest single asset of the whole page is the background image, I really wanted to use multiple background images to make sure that the closest possible image size is served to the user.

This most likely has zero use to you, but I thought it was a really interesting implementation of RESS multiple background images using media queries and Sass. I hope that if you need it, you use it; and if you don’t need it, maybe it will inspire you to employ some of Sass’s more advanced functionality.

Supporting Mixins

In your mixin library, add these mixins:

// if/else that builds the actual media query. Usage:
// .selector {
//   @include mq(40em) {
//     some style rules;
//   }
// }
@mixin mq($breakpoint) {
    @if $breakpoint == 40em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
    @else if $breakpoint == 48em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
    @else if $breakpoint == 62em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
    @else if $breakpoint == 78em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
    @else if $breakpoint == 86em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
    @else if $breakpoint == 92em {
        @media only screen and (min-width: $breakpoint) { @content; }
    }
}
// adapted from http://www.impressivewebs.com/modular-css-media-queries-sass/

// This mixin generates the actual CSS
@mixin ress-background-images($themeName, $bodyBG, $bodBGFormat) {
    background: url(#{$themeName}/images/#{$bodyBackground}.#{$bodyBackgroundFormat}) no-repeat center top;

    @include mq(30em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-40em.#{$bodyBackgroundFormat});
    }

    @include mq(40em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-48em.#{$bodyBackgroundFormat});
    }

    @include mq(48em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-62em.#{$bodyBackgroundFormat});
    }

    @include mq(62em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-78em.#{$bodyBackgroundFormat});
    }

    @include mq(78em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-86em.#{$bodyBackgroundFormat});
    }

    @include mq(86em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-92em.#{$bodyBackgroundFormat});
    }

    @include mq(92em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-2x.#{$bodyBackgroundFormat});
    }

    @media
    only screen and (-webkit-min-device-pixel-ratio: 2),
    only screen and (   min--moz-device-pixel-ratio: 2),
    only screen and (   -moz-min-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) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-62em.#{$bodyBackgroundFormat});
    }

    @media
    only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 40em),
    only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 40em),
    only screen and (   -moz-min-device-pixel-ratio: 2)      and (min-width: 40em),
    only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 40em),
    only screen and (        min-device-pixel-ratio: 2)      and (min-width: 40em),
    only screen and (                min-resolution: 192dpi) and (min-width: 40em),
    only screen and (                min-resolution: 2dppx)  and (min-width: 40em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-78em.#{$bodyBackgroundFormat});
    }

    @media
    only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 48em),
    only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 48em),
    only screen and (   -moz-min-device-pixel-ratio: 2)      and (min-width: 48em),
    only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 48em),
    only screen and (        min-device-pixel-ratio: 2)      and (min-width: 48em),
    only screen and (                min-resolution: 192dpi) and (min-width: 48em),
    only screen and (                min-resolution: 2dppx)  and (min-width: 48em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-86em.#{$bodyBackgroundFormat});
    }

    @media
    only screen and (-webkit-min-device-pixel-ratio: 2)      and (min-width: 62em),
    only screen and (   min--moz-device-pixel-ratio: 2)      and (min-width: 62em),
    only screen and (   -moz-min-device-pixel-ratio: 2)      and (min-width: 62em),
    only screen and (     -o-min-device-pixel-ratio: 2/1)    and (min-width: 62em),
    only screen and (        min-device-pixel-ratio: 2)      and (min-width: 62em),
    only screen and (                min-resolution: 192dpi) and (min-width: 62em),
    only screen and (                min-resolution: 2dppx)  and (min-width: 62em) {
        background-image: url(#{$themeName}/images/#{$bodyBackground}-2x.#{$bodyBackgroundFormat});
    }
}
// retina media queries adapted from http://css-tricks.com/snippets/css/retina-display-media-query/

As complicated as that looks, it’s actually quite simple. This mixin takes your breakpoint min-width and builds the media query using it. I am sure this could be made more flexible by adding one more parameter, but there’s no need for me right now. It can also be customized to fit your breakpoints. Not using ems? Replace my values with px values. It also uses Sass’s @content directive, which passes content into a mixin.

Necessary Variables

Now we need to create our variables. Since I wanted to be able to change the background image by changing only variable values, I needed three different variables:

// Each theme is stored in a different folder, so this is the root folder name of the theme
$themeName: clouds;
// This is the name of the background image, sans width and file type
$bodyBackground: body-bg;
// This is the format of the background images. I added this because I needed to be able to use both JPGs and PNGs
$bodyBackgroundFormat: png;

This gives us everything we need to generate our actual CSS from this Sass:

Using the Mixin in Your SCSS File

// This is the code in your SCSS file.
body {
    @include ress-background-images($themeName, $bodyBackground, $bodyBackgroundFormat); 
}

Since Sass combines all the media queries of the same parameters, I can have this block of code in every theme and know I’m not creating more complex CSS. It’s a very simple way to use multiple background images based on screen width. Using this code means I can copy and paste this Sass and generate all of this CSS:

body {
    background: url(clouds/images/body-bg.png) no-repeat center top;
}

@media only screen and (min-width: 40em) {
    body {
        background-image: url(clouds/images/body-bg-48em.png);
    }
}

@media only screen and (min-width: 48em) {
    body {
        background-image: url(clouds/images/body-bg-62em.png);
    }
}

@media only screen and (min-width: 62em) {
    body {
        background-image: url(clouds/images/body-bg-78em.png);
    }
}

@media only screen and (min-width: 78em) {
    body {
        background-image: url(clouds/images/body-bg-86em.png);
    }
}

@media only screen and (min-width: 86em) {
    body {
        background-image: url(clouds/images/body-bg-92em.png);
    }
}

@media only screen and (min-width: 92em) {
    body {
        background-image: url(clouds/images/body-bg-2x.png);
    }
}

@media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-moz-min-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) {
    body {
        background-image: url(clouds/images/body-bg-62em.png);
    }
}

@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 40em),
only screen and (min--moz-device-pixel-ratio: 2) and (min-width: 40em),
only screen and (-moz-min-device-pixel-ratio: 2) and (min-width: 40em),
only screen and (-o-min-device-pixel-ratio: 2 / 1) and (min-width: 40em),
only screen and (min-device-pixel-ratio: 2) and (min-width: 40em),
only screen and (min-resolution: 192dpi) and (min-width: 40em),
only screen and (min-resolution: 2dppx) and (min-width: 40em) {
    body {
        background-image: url(clouds/images/body-bg-78em.png);
    }
}

@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 48em), 
only screen and (min--moz-device-pixel-ratio: 2) and (min-width: 48em), 
only screen and (-moz-min-device-pixel-ratio: 2) and (min-width: 48em), 
only screen and (-o-min-device-pixel-ratio: 2 / 1) and (min-width: 48em), 
only screen and (min-device-pixel-ratio: 2) and (min-width: 48em), 
only screen and (min-resolution: 192dpi) and (min-width: 48em), 
only screen and (min-resolution: 2dppx) and (min-width: 48em) {
    body {
        background-image: url(clouds/images/body-bg-86em.png);
    }
}

@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 62em), 
only screen and (min--moz-device-pixel-ratio: 2) and (min-width: 62em), 
only screen and (-moz-min-device-pixel-ratio: 2) and (min-width: 62em), 
only screen and (-o-min-device-pixel-ratio: 2 / 1) and (min-width: 62em), 
only screen and (min-device-pixel-ratio: 2) and (min-width: 62em), 
only screen and (min-resolution: 192dpi) and (min-width: 62em), 
only screen and (min-resolution: 2dppx) and (min-width: 62em) {
    body {
        background-image: url(clouds/images/bodyBackground-2x.png);
    }
}

Have you employed Sass in any new awesome ways we should know about? If so, link to them in the comments.