How to Use Responsive Background Image Sprites – CSS Tutorial

At one time or another, you may have found yourself wanting to use sprites in your responsive website design. While at first this may seem like a very simple task, in reality it’s a little more difficult of a challenge. It can, however, be done. Here’s how! This trick is fully supported by all modern browsers other than IE 8 and earlier, in which the image resizing aspect will not work properly, though it will not break completely.

Let’s start with our HTML. Let’s say we have part of a website here, and what we want is for the background image of this div to change when we hover over it. The catch is that we are using a sprite for it (a single image containing both our normal and rollover images) and it’s a responsive design. Let’s take a look.

Truly groundbreaking.

Okay, the html isn’t really that relevant I realize now. I could make it more fancy to try to make it a “real world example,” but why bother? Keep it simple, stupid.

The secret is clearly all in the css. Let’s say this div is always a square,  using our trick to maintain the same aspect ratio for an element in a responsive design. This might be the CSS of the element before we’ve added the background image.

Now we have a square image we want to nestle nicely inside there. And when we rollover the element, we want it to change. How do we do that? By adding the following css:

Now here’s what’s really interesting about the background-size property. It does not STRETCH the image in both directions, it assumes that the image fits perfectly WIDTH-wise into our container, and then calls that 100%. If we want the image to be larger than what actually fits in the container, we go bigger. If we want it to be smaller and have to repeat, we go smaller. In our case, let’s say our image is 1000px wide and 500px tall. On the left 500px we have the first image, on the right 500px we have the rollover image. If we were to leave the setting at background-size: 100%;, we would end up with the image fitting completely within the div and repeating itself once underneath.

We don’t want this, however. We want the first half of the image only to fit. So we set background-size: 200%;, since we need it to be twice as large as the space we have assigned for it, since we only want the first half of the image to fit in our div.

Now it’s time to set everything up for the hover state. To do that, we add this to our css:

The only thing we need to change is the background position! The secret is to place the background image using only percents. This is what allows it to be responsive. Actually USING this positioning system can be a little confusing, so let me break it down for you.

Calculating the background position

This is actually quite complicated and not at all intuitive. The best way I can explain it in words is this: the distance between 0% and 100% for your background position is the distance between when the left edge of your background image is touching the left edge of your element, and when the right edge of your background image is touching the right edge of your element.

So let’s break this down into a formula I came up with. This formula assumes each image in the sprite is the same size, and that each image is the same size as the element (i.e.: fits it exactly).

Percent Increments to Use = 100% / (Discrete images in your sprite – 1)

So if you have 4 images in your sprite: 100% / (4-1) = 100% / (3) = 33.33333%

So to display the first image, you set background-position: 0 0;. The second, background-position: 33.33333% 0;. And so on. Again, it’s not that intuitive, but with the formula it’s a little easier.

Let’s Consider another example. You have FIVE images in one sprite that you wish to use, all in a row. You want to display the SECOND image in the row. What background position do you use? Well… 100% / (5-1) = 25%. So if I wanted to display the second image, I would have to use background-position: 25% 0;. Easy!

If you would like to see a real-life and real-creepy example I made using my own face, check it out here!

About Brian Johnson

Brian Johnson is a website developer and designer living in Minneapolis, Minnesota with a passion for code and WordPress. He spends his days building WordPress websites for small businesses, developing new code with the online community, and living life.

84 Comments on “How to Use Responsive Background Image Sprites – CSS Tutorial”

  1. Hello Brian,

    i have a css sprite with 8 pictures in it,
    each has width: 115px, height: 115px, left to right in total: 920px.
    it works successfully with this code:

    html:

    css:
    .sprite {
    background:url(multipic.jpg) no-repeat;
    width:115px;height:115px;
    }

    #pic1 {background-position:-0 -0;}
    #pic2 {background-position:-115px -0;}
    #pic3 {background-position:-230px -0;}

    But now – for another purpose – i want to display it
    with smaller dimensions.
    That’s why i read your website yesterday with great pleasure.
    This is my new code for the first picture, copied from jour website:
    html:

    css:
    div.smallsprite {
    width: 20%;
    height: 0;
    padding-bottom: 20%;
    background-image: url(multipic.jpg);
    background-position: 0 0;
    background-size: 800%;
    display:block;
    }

    Unfortunately, no picture is displayed.
    Where is the mistake?
    I ask for your support!

    Kind regards

    1. My guess is that the parent element has no width. The size calculated by “width: 20%;” and “padding-bottom: 20%;” are both determined by the width of the parent element. If it has no width, then this element will not show.

      If you set up a fiddle with it I can maybe take a closer look. Hard to troubleshoot otherwise.

  2. Brilliant! Could not work out how to both contain the background image and use sprites. This works perfectly. Thank you.

  3. Brilliant! Could not work out how to both contain the background image and use sprites. This works perfectly. Thank you.

  4. Hey Brian, so cool how you are helping out with this resource!

    Wannabe “try to fix my own code” here! Been spending a gazillion hours trying to get my first css sprites in place – which I finally did – but when I see them Implemented the seem to move 1 px (see the three pics right under the fold – this didn’t happen when I tried it outside of my page). I used this website to generate the sprite and code http://responsive-css.spritegen.com/

    Is it easy for you to tell why it happens? Is this something that happens aaaaall the time? Any fix that comes to mind? Thanks a million

    1. I have seen that as an issue before! One trick We’ve seen to fix this is to just make the background very slightly larger than it needs to be. So calculate what percentage would essentially be 1px and add that on. Sometimes you might need to tweak other things slightly to get it all to work perfectly, but that should do the trick I believe. Other times, having things overlap that white space works, too.

  5. Hi Brian,

    Confusing myself with this one.

    I have an image on top of another images in a vertical stack. 1320×992 when together. Just want a 1320×496 image to show at first and then the other below it on rollower.

    At the moment I have

    div.sprite2 {
    margin:0 auto;
    width: 100%;
    height: 0;
    padding-bottom: 100%;
    background-image: url(“../img/image1.jpg”);
    background-position: 0 0;
    background-size: 200%;
    display:block;}

    div.sprite2:hover {
    background-position: 0 -100%;
    background-size: 200%;
    }

    Which makes the initial image way too big. Can you explain (in idiot terms) please how to make the images the correct size

    1. Hi there,

      I believe “background-size” when only setting one value actually specifies the width of the image. The height will follow in proportion (it doesn’t stretch it). So you actually want that set to 100% because your image is already the right width. And don’t change it on hover.

      I think that’s all you need to do, actually. Should work after that! Rest of your code looks right.

      1. Cheers Brian,

        Got it working. I was making the calculation the wrong way round.

        div.sprite2 {
        margin:0 auto;

        width: 100%;
        height: 0;
        padding-bottom: 37.5758%;
        background-image: url(“../img/image1.jpg”);
        background-position: 0 0;
        background-size: 100%;
        display:block;}

        div.sprite2:hover {
        background-position: 0 100%;
        background-size: 100%;
        }

        An interesting one with this techniques is I tried adding css effects to the images (just for fun). The hover image works well with an animation because when you rollover it it gets called but when you roll off you get no anim when it goes back to the normal image.

        I used to used this technique when the image size was fixed.

        .test {display: block; position: relative; text-indent: -9999px; width: 1320px; height: 496px; background: url(../img/image1.jpg) no-repeat; overflow:hidden; }

        .test:after {content: “”; position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: url(../img/image1.jpg) no-repeat; background-position: 0 -496px; opacity: 0;-webkit-transition: opacity 0.5s; -moz-transition: opacity 0.5s; -o-transition: opacity 0.5s; -ms-transition: opacity 0.5s;}

        .test:hover:after {opacity: 1; -webkit-animation: filter-animation 2s 1}

        @-webkit-keyframes filter-animation {
        0% {-webkit-filter: saturate(200%) brightness(200%);}
        50% {-webkit-filter: saturate(100%);}
        100% {-webkit-filter: saturate(100%);}
        }

        This led to a nice roll over roll off effect but the issue here was it was not responsive. Brians movement technique works great with the rollover effect but then fails on roll off for some reason. (I am assuming because it is just a movement changes not a new call to the effect.

        .test3 {display: block; position: relative; background: url(../img/image1.jpg) no-repeat; overflow:hidden; width: 100%; height: 0; padding-bottom: 37.5758%;background-size: 100%; }

        .test3:after {content: “”; position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: url(../img/image1.jpg) no-repeat; background-position: 0 100%;background-size: 100%; webkit-transition: opacity 0.5s; -moz-transition: opacity 0.5s; -o-transition: opacity 0.5s; -ms-transition: opacity 0.5s; }

        .test3:hover:after {opacity: 1; -webkit-animation: filter-animation 2s 1}

        @-webkit-keyframes filter-animation {
        0% {-webkit-filter: saturate(200%) brightness(200%);}
        50% {-webkit-filter: saturate(100%);}
        100% {-webkit-filter: saturate(100%);}
        }

        Also the :after does not seem to with with Brians technique. (I am probably doing something worng).

        Brains techniques is better due to its responsiveness but would be interested to here if anyone has an idea on how tofix the rolloff issue.

        Cheers for any help.

        1. Sussed it. This seems to work.

          .test2 {color:#fff; display: block; position: relative; background: url(../img/image1.jpg) no-repeat; overflow:hidden; width: 100%; padding-bottom: 37.5758%; background-size: 100%; height: 0; opacity: 1;-webkit-transition: opacity 0.5s; -moz-transition: opacity 0.5s; -o-transition: opacity 0.5s; -ms-transition: opacity 0.5s;}

          .test2:after { color:#fff; content: “”; position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: url(../img/image1.jpg) no-repeat; background-position: 0 -496px; opacity: 0;-webkit-transition: opacity 0.5s; -moz-transition: opacity 0.5s; -o-transition: opacity 0.5s; -ms-transition: opacity 0.5s; padding-bottom: 37.5758%; height: 0; background-position: 0 100%; background-size: 100%; }

          .test2:hover:after {opacity: 1; -webkit-animation: filter-animation 2s 1; background-position: 0 100%; background-size: 100%; width: 100%; padding-bottom: 37.5758%; color:#fff; }

  6. Nice article but I am looking for a solution for a sprite that contains serveral images in different sizes, and using this method that’d be too complicated to achieve.

    1. That’s actually very doable using this same solution! I’ve done it many times. The only difference is that the formula doesn’t work quite the same. You need to utilize the total number of pixels across the whole image, and then calculate how many pixels come before and after your chosen image and get the percent values for that. It’s definitely more complicated. I’ve thought about building a tool where you enter the sizes of every image in your sprite and then it will spit out the proper CSS. Haven’t done it just yet…

      Alternatively, you can just enter in guess values and just adjust them until you get it right. More time consuming, but it works just fine!

  7. Hello Brian, thanks for this article. I want to sprit a vertical icon for option car. I see only the first. This my css

    .sprite{
    height: 33%;
    width: 20px;
    padding-bottom: 17%;
    display: inline-block;
    background-image: url(‘img/sprite_options_auto.jpg’);
    background-position: 0 0;
    background-repeat: no-repeat;
    display:block;
    }

    .sprite .vehicule-clim { background-position: 0 0; }
    .sprite .vehicule-boite { background-position: 17% 0; }
    .sprite .vehicule-porte { background-position: 34% 0 ; }
    .sprite .vehicule-passager { background-position: 51% 0 ; }
    .sprite .vehicule-bagage { background-position: 68% 0 ; }
    .sprite .vehicule-motorisation { background-position:100% 0 ; }

    i use bootstrap 4

  8. I want a sprite in a horizontal row of four 32px X 32px images for my social icons. I have background-repeat: no repeat; background-size: 400%; and used your formula for the background-position for each individual image. Instead of seeing each image the first image repeats itself four times. Any suggestions? Thanks!

    1. Thanks for your response. I fixed it. I had forgotten that I had padding between the images so the image+padding size didn’t correspond with the image sizes in the css.

  9. Thanks, you saved my time! I was trying to convert size into em but your method is the easiest solution. However, I would suggest to keep at least couple of pixel white space around each frame because calculation sometimes give one pixel error and you may see little part of another frame. Adding extra 5-10 pixel space between sprite should not cause any problem.

    1. As per the formula in my page, you would move each image by an additional 100% / 86-1 = 1.17647%. The first image would be at 0, the second at 1.17647%, the third at 2.35294%, etc. Note, however, that this only applies if all of your sprites are the same size, and they are all in a row. If they aren’t all in the same row, then you are going to need to do these calculations but for both x and y based on which image they are in each row/column.

  10. very nice. thank you for this. I find the method used to calculate the exact background position great.

  11. This solution works fantastic in all browsers, but in IE and Edge every image is blurry and pixelated, forcing me to abandon the sprite and having separate individual fixed sized images for IE and Edge. My responsive design CSS is as follows:

    Here is a typical example:

    .sprite-24 {
    display: inline-block;
    width: 24px;
    height: 24px;
    background-size:1200%;
    }

    .sprite-img.sprite-24.change_icon {
    background-position: 54.54% -24px;
    }

    In this example, I am using 12 beautiful 512×512 image icons and using responsive design to display them at various sizes, 24×24 in this example. The images look gorgeous and even more beautiful when the browser is zoomed. But in IE and Edge the images are horrible. Those browsers simply don’t seem to support responsive design using the background-size property. Any thoughts would be much appreciated, and thanks again for the great tutorial.

    1. Nice to see Microsoft has learned exactly nothing from the failure of their old browsers… Honestly, I’m not sure how to avoid that! I imagine they think they are smarter than other browsers by rendering a smaller version of the image for some reason, but… Ya, I have no idea! How annoying.

  12. Pingback: How to create a responsive sprite sheet animation in css? - Tech Magazine

  13. I just used this after fiddling for hours with icon fonts and what not!!!! THANK YOU!!!!
    Just to add you have to change the background size to multiply by how many icons you have. So, I had 5 icons, the background size was 500%

  14. Pingback: responsive sprite background image, how to - DexPage

  15. Pingback: How to Make Any Website Responsive

  16. Hello. Nice Tutorial. But what is, if i don’t have only squares, what so often is the case, instead diferent sizes of images?

    1. You just adjust the width or padding as necessary. To make it twice as wide as it is tall, you might set it to 40% width and 20% bottom padding. Then just follow the formula to figure out how to use your background sprites.

  17. Pingback: [Responsible web] 반응형 웹에서 Image Sprite 사용하기 | Happy Javascript

  18. Great Tutorial, Thank you so much for this !!!

    just one question: can you further explain the logic behind choosing 33.3333 as a background-position when using 4 frames ?
    and how can we generalize this for n frames ?
    is there some kind of formula or it is about testing ?

    1. It’s a really confusing concept, but basically the percentage is simply the percentage of how far the image can travel before the other corner of the image is reached.

      This may sound strange, but let me explain it this way. If you had an element that was 100px wide, and a background image that was 100px wide, background-position would do literally nothing if you tried to use percentages. Because all 4 corners are already touching.

      Now let’s say you had an element 100px wide, and an image 101px wide. Background-position:100% 0; would only move the image a single pixel. Because the total distance it can move before the other end of it is lined up with the element is one pixel. Likewise, if you had an element 100px and an image 200px wide, then 100% would move it 100px. 50% would move it 50px.

      So let’s say we have a sprite with 4 different images on it. It’s 400px wide. And our element is 100px wide. First, let’s figure out what the total distance it can travel before the other end of the image is lined up with the edge of our element. 400-100 = 300px. So 100% = 300px.

      So if 100% is 300px, and we want to move our sprite 100px at a time, what percentage increments do we use at a time? 100/3 = 33%!

  19. Wow, didn’t think I’d be able to find a solution for this, but this worked perfectly. The zero height and bottom padding was the part I was missing, thanks a lot.

  20. Hi Brian ,
    Thanks, this helped me a lot. But one thing bothered me – somethies I need use max-width and min-width to my image.

    I found way to do this and I just want to share it with You:

    .sprite_container{
    width: 30%;
    max-width: 400px;
    min-width: 200px;
    }
    .sprite{
    width: 100%;
    padding-bottom: 45%;
    background: URL(‘sprite.jpg’);
    background-size: 200%;
    background-position: 100% 0%;
    }

    One thing to mention:
    padding-bottom of ‘sprite’ div is proportion of single image(not whole sprite) width to single image height, so:

    .sprite {
    padding-bottom: (image.width/image.height) %;
    }

    Let me know what You think about it,

  21. HI Brian. Thanks for the tutorial. I’ve been looking at several sites for responsive sprites and yours was the easiest to follow. However, I can’t seem to get my head around the CSS needed for say, two different people side by side with alternate images beneath and hovering over would only change the image of the face you hover over. I made your sprite work vertically but not vertically and individually. I assume I would need to set up an unordered list to do it but haven’t been able to come up with the right CSS.

  22. Hello Brian, I am having trouble positioning my responsive sprite. I am sort of a beginner so it might be something really simple that I’m not recognizing. I want to maintain the same aspect ratio to the top and left of my browser window. Right now when my height is adjusted the sprite moves from my intended spot. I tried adding padding-top to the css but that did not work. Thanks for any help or advice you have.

  23. This is the first article that I’ve seen on responsive sprites. I thought it was possible, but now I know its possible. #GoodStuff

  24. Hi and thank you for the nice tutorial. There is not much for this topic when I google as I have been doing for a few days now. I think your tutorial comes up directly or is referenced in about a third of the search results. I have a question, though, if I may:

    I have plugged the code in and altered the shape a bit for my image and that works perfectly, but what I want to do with it is make a menu with a unique sprite for each item. I’ve made such in the past, but it was not responsive and, though I have tried to make this technique work by plugging it into ul/li properties, I have been failing miserably. Can this be made into a menu and, if so, what would the css look like?

  25. Brian, first off this is some great stuff! Very helpful post. The main issue that Im having with this is image wobble for cross-browser support. I feel confident that I’ve done the math correctly, but I assume that at different resolutions, different browsers are treating the % shifts by either rounding the pixel value up or down (creating the wobble). How have you dealt with this in your implementations?

    You can see an example here:
    It works wonderfully in Chrome (which handles sub-pixel values) at almost all resolutions, but seeing issues in Safari, some FF and IE9+. Any advice you might have would be appreciated!

    1. It looked like it was working fine to me! The browsers seemed to work differently in terms of how they resized things live during browser resizing, but seemed pretty consistent while the browser size was static.

  26. This is an awesome solution, thanks so much Brian! One item I am troubleshooting, when I use this sprite method my image is ever so slightly blurry. Any clue what this might be?

    1. Make sure the actual image size is the exact correct dimensions. If it’s even a pixel off, it will display blurry. I recommend inspecting the image element in your browser and verify what size it’s actually displaying at, and comparing that to the actual image file.

    2. I too had similar problem of images being blurry. My case was I had to target both retina display and normal devices using same image sprite file. This caused my image files to be double the dimension. I solved this issue by adding a 2px border on all images as per their background image on Photoshop (not using CSS). For me my background was white, so I added 2px white border on all images. And the blurry issue was gone.

  27. After an hour of playing with this conclude that it doesn’t work for me. Using a single large icon sprite (250×250) and the pixel shift on rollover is beyond acceptable parameters with IE and FF. Cannot test with your demo as the image changes entirely – might be useful to post a demo with a simple rollover icon color change so can test properly. But for now I’m back to square 1.

    1. at 40% the shift is in your face – at 36% it’s barely noticeable. Something to do with math I guess 😉

        1. If you are getting any kind of shift, odds are you are not doing the math correctly. You need to be exact. Depending on what you are attempting, it’s entirely possible you need to be getting down to the fraction of a percent. Again, the shift itself is hard to wrap your head around, you may be doing it incorrectly. Perhaps share your code on a js fiddle so I can see what you are dealing with and how to fix it.

  28. I’ve been looking for days for a solution to responsive sites with css sprites. Thank you for coming up with a great solution! SO helpful.

  29. Unrelated but interesting to note:
    I think using background-size: cover; works the same as 100% 200%; etc. it stretches the image till the div is filled and leaves out whatever is left (the other half of the sprite). It worked fine for my 16-part sprite if I’m not mistaken.

  30. I have the same problem as the previous 3 coments…on FireFox on Mac/Linux… a slight shift and it even shows a sub-pixel black or grey border on one or two sides of ‘some’ of the divs. I have a 16-part sprite with 8 responsive divs and rollover. FF is the only browser that remembers the sub-pixel amounts after the decimal (like .666%) in case the div relies on one to its left….it adds them together when needed. My divs are often 80.2444px wide by 40.2482px high and those extra bit get a shade applied to them somehow! Bummer. Might have to split the sprite into 8 sprites and try the simpler approach.

  31. This is a simple and effective implementation, yet it has the same problem as the other “responsive sprites” implementations I’ve encountered.

    The problem is non-chrome browsers will render a fraction of pixel from the next image. When you only have few images in a sprite and they both have same background this won’t be noticed, but when you have 20 images, the background will be wrong with a 20 times that fraction of a pixel, anywhere from 0 to 19.999px.

    I think the bug appears because most browsers round the sizes of elements to integers, but still use the raw number for percentage calculations. Chrome is the only one that works fine in this regard.

    I don’t know any fix for this, but I wish I did.

  32. Thanks for posting this article! It provided just the missing piece to a puzzle I’m currently working on. 🙂

    One question: during my testing, I’ve found in Firefox 25 (on Linux) one of the background changes causes a noticable “shift” in the background image. This doesn’t happen in Chrome 31, on the same system.

    My sprite is a JPEG image, 600×400 in dimension. I have four images in it, with each “normal” and “hover image in a row.

    The first row of images display and behave just fine in both Firefox and Chrome. The second row of images causes the “shift” behavior in Firefox that doesn’t appear in Chrome.

    Would you have any remote idea as to why this might be happening? The issue is a lot worse in Opera 12, but considering Opera 12 is pretty much dead, I won’t worry about it too much. At least not until I get the Firefox issue resolved. 🙂

    Thanks in advance!

    Peace…

  33. AWESOME! Everywhere else they said it couldn’t be done, or they had some javascript answer that may or may not work. This is an amazing solution! Thank You. My only other wish would be for Microsoft to give up on making browsers!

  34. Thanks for this great article.

    Everything up until the last paragraph was really helpful. But I had to do quite a bit of fiddling around until I understood exactly how images wider than 2 columns work. Unfortunately, I’m not entirely sure how to put it into words.

  35. hmmmmm I dont get it, I think I need to learn some part
    before this one. Thanks for Sharing, gonna bookmark this page
    so that I know were to find this.

  36. Wanted to check to see if you have heard of any Way to also support IE8. Would love to start using this but still have to support IE8.

    1. No problem! And I agree, it’s hard to find good resources about it. Glad I could help! Let me know if you have any other questions and I’ll do my best to answer.

  37. Pingback: How to Make CSS Image Sprites Responsive | Netmajic Social Media

Leave a Reply

Your email address will not be published. Required fields are marked *