HTML5, CSS3, jQuery, JSON, Responsive Design...

Responsive CSS Sprites

Michael Brown   May 4 2014 02:36:00 AM
On my earlier post Rocket your website speed with CSS sprites!, I showed (I hope!) how can really speed up your page load times by loading a single, combined sprite image instead of multiple individual images.  As I said at the near the end of that post, however, things get a little trickier when you have to take Responsive Web Design into consideration.

Let's examine the two pages again.  This time I've added a media query to them both.  The media query kicks in when your browser width drops below 700px, so you just need to drag the edge of your browser in to see the effect.  Or if in Firefox, use Ctrl->Shift->M (Command->Alt->M to call up the Responsive Design View.

Here's the CSS:

@media all and (max-width: 699px) {
     .flag {
             width: 32px;
             height: 21px;
     }
}


All it does is set the elements to be half of their normal size.  Let's see how it works in the multiple img tag version first:

http://www.users.on.net/~mikeandgeminoz/spritetest/index2.html

No probs there.  The flags all reset to half size, and the flags are shrunk down nicely with them.  No let's try the CSS prite version with the same media query code:

http://www.users.on.net/~mikeandgeminoz/spritetest/index.html

Woah!  What's going on here?  The flag div tags are resizing okay when I narrow the browser's width, but the sprite images aren't.  Suddenly, we have an abundance of Union Jacks!  That's because instead of resizing the images, the CSS code is cropping them instead.  So the Australian flag loses all its stars, and we're just left with the Union Jack at the top left.  (What's that at the back?  "That's actually an improvement", you say?  Well, you may have point there, but...)


So is there way that we can resize the sprite divs and have their images resize correctly too?  Yes, there is, but it takes little bit of work.  The only way that I could find to do it is to specify the image sizes as percentages instead of pixels.


Percentage for Sprites

For the calculations on how convert pixel values into percentages, I followed this Stack Overflow thread.  Particular thanks to vals, who got me most of the way there, although there were some errors in his calcs.  I posted my corrections (as ChillyPenguin) on the same thread.

First off, you have to add a new CSS attribute to your divs.  This is called background-size, and it has to be set as a percentage.  It takes X and Y values, and the percentage calculations go like this:
x percentage width = (total image width / display image width) x 100
y percentage width - (total image height / display image height) x 100


My combined flags image is 1110px wide by 799 px high.  My flags sizes (handily, all the same) are 64px wide by 42px high.  So the background-size values go like this:
x percentage width = (1110 / 64) x 100 = 1734.375%
y percentage width - (799 / 42) x 100 = 1902.380952%


Because all my flags are the same size, I can apply to background-size attribute to a flag class, which I add to all my flag divs:
.flag {
      display: inline-block;
      background: url('../images/sprite.png') no-repeat;
      width: 64px;
      height: 42px;
      background-size: 1734.375% 1902.380952%;
}



Now the hard bit: we have to reset the background-position attributes on all of the flags.  So here's the calcs for that:
x percentage pos = (x pixel pos / (total image width - display image width)) x 100
y percentage pos - (y pixel pos / (total image height - display image height)) x 100


So for my first flag, which is Afghanistan, my absolute background size looks like this:
.flag.flags-afghanistan {
      background-position: -5px -0px;
}


So the percentage calc for the x dimension goes.  Note that the negative x pixel position is converted to positive when you do the percentage calculation:
x percentage pos = (5 / (1110 - 64) x 100) = 0.4780114723%


The y percentage is zero in this case, because the pixel y position is also zero.  Here's the resulting background-position code:
.flag.flags-afghanistan {
      background-position: 0.4780114723% 0;
}


Phew!  Got there.  Repeat and rinse for all the other flags, and here's the result: fully responsive sprite images!!

http://www.users.on.net/~mikeandgeminoz/spritetest/index3.html

Note: I've reduced it to only eight flags to try and prevent RSI!!  Yes, the calculations are fiddly but you ought to be able to set up a simple spreadsheet to help you.






Comments

1Quique  06/22/2014 4:09:25 PM  Responsive CSS Sprites

Thank you for the post.

I think there's a error on the example, when you wrote the dimensions. In the next operation are written the dimensions of Y (799 and 42) instead of the X dimensions (1110 and 64).

"x percentage pos = (5 / (799 - 42) x 100) = 0.4780114723%"

2Mike Brown  06/23/2014 7:16:26 AM  Responsive CSS Sprites

@Quique

Well spotted.

I've now corrected the error with the x-axis figures.

3minjeong  09/24/2014 1:49:32 AM  Responsive CSS Sprites

Thank you for the post a lot! :-)

This is amazing! I had been looking for this(Responsive image sprite).

I used it to mobile page and it works perfectly!

:-)

4Seme  10/07/2014 8:05:18 PM  Responsive CSS Sprites

Thank you for the post.

I finally get a responsive sprite working. However, I am trying to find a way to automatically keep the aspect ratio of the image preserved while it is being resized. So far, no luck !!

The sprite image is inside an <a> element which contains only text and <i class='sprite-img'></i>. I am using padding-right to change the width of the sprite image. However, only the width changes, while the height remains the same. The desired behaviour is to keep the aspect ratio while the image is being resized.

<a >

<i class='sprite-img'></i>

Link Text

</a>

a{

display:inline-block;

font-size:16pt;

}

.sprite-img{

background: url("sprite5.png") no-repeat scroll 14.085% 60.496% / 171.717% 2767.69% rgba(0, 0, 0, 0);

padding-right: 50px;

}

5Mike  01/18/2016 6:55:53 PM  Responsive CSS Sprites

Thanks Brownie. Your work was brilliant!

To make it scaleable, i use "aWebDeveloper"'s idea:

https://stackoverflow.com/questions/2430206/how-can-i-scale-an-image-in-a-css-sprite/16080995#16080995

I suppose that will keep the aspect ratio. Not sure that's the right way to do it. I'm not a programmer by trade.

Again. Thanks Brownie

6Jimmy  01/23/2016 11:14:51 PM  THANK YOU!

Thanx Brownie!

I read Vals' answer on Stack Overflow but yours is more detailed.

In my <a href="https://jimmydance.com/" target="_blank">website</a> (MEDIA--> GALLERY) you can see what I've done!

Sometimes (not always) images look bad nested but definitely better than before!!! Is there anything I can do about?

About