27

I've read every single question about responsive sprites using css, I saw jsfiddle with working examples of responsive sprites, but I still cannot understand how to get the percentage of background-position and of background-size, how to use a wrapper (some people say it is necessary) around the div that uses background-image and why to use it...
For instance, if I have a div that has width:20% (say 40px) and is a circle. The image I need to use as background-image has 80px width (a circle, and I need to resize it to fit my div) and is one of the 40 images I have in my sprite sheet. It is at the position -173px -293px.
I really have no clue how to make it work.
I tried:

div {
  width:20%;
  border-radius:50%;
  background: url('images/sprites.png') no-repeat 72.083% 67.981%;
  background-size: 50%;
  }

Of course, it did not work. I don't understand how to get the background-position-x, background-position-y (the numbers I have are from the "auto" size sprite sheet) when the background-size is not auto, or how the background-size relates to the percentage of the div size.
Is there any mathematical formula that I can use? Can anyone please explain me or give me a name of some website/book where I can learn it?
Thanks,

user3097405
  • 783
  • 1
  • 6
  • 15
  • Possible duplicate of [How can I scale an image in a CSS sprite](https://stackoverflow.com/questions/2430206/how-can-i-scale-an-image-in-a-css-sprite) – KyleMit Sep 05 '18 at 04:12

9 Answers9

30

An update to @vals' answer. Some of his calcs didn't quite work for me.

The background-size calcs worked, except that he was multiplying by 1000 instead of 100 to get the final percentage figures. So 12500% should be 1250% and so on. (Update: 10/2015 - it looks like @vals has corrected this in his answer.)

The background-position X value calcs were very slightly out for me. They didn't match what was generated by spritecow.com (as per Adrian Florescu's suggestion). This is, I think, because absolute coordinates are calculated from the left of the background image, whereas with percentages, you have to calculate from the right of the background image. That being the case, you have to subtract the image width from the overall background width before you divide the absolute x-pos number with it.

So instead of:

x-part 173px / 1000px = 0.173 ->> 17.3%

do this:

x-part 173px / (1000px - 80px) = 0.1880434783 ->> 18.80434783%

Where:

1000px is the width of the background image (sprite)

80px is the width of displayed image

173px is the absolute x-coordinate of the displayed image.

This is what works for me, anyway!

ChillyPenguin
  • 1,090
  • 11
  • 17
19

The div dimension doesn't play in the calculus, only the background sizes, and the part that you are going to use.

Lets say that your background has a width of 1000px and a height of 500px.

The image that you are going to use has 80px width and height.

background-size:

x part     1000px / 80px = 12.5   ->> 1250%
y part      500px / 80px = 6.25   ->>  625%

background-size: 1250% 625%;

background-position:

x-part     173px / 1000px = 0.173   ->> 17.3%
y part     293px / 500px = 0.586    ->> 58.6%

background-position: 17.3% 58.6%;
vals
  • 54,758
  • 10
  • 75
  • 124
16

I've written a Responsive CSS Sprite Generator to take care of all the work for you. You can just upload a bunch of images and it will give you a sprite image and the CSS for it.

It uses a novel method for making the sprites responsive - a data src with a transparent PNG to make the image maintain its aspect ratio, so unlike other methods the images don't need to be square, or all the same ratio.

Greg
  • 295,929
  • 52
  • 357
  • 326
  • 1
    Your generator is awesome! It helped me understand responsive CSS-sprites a great deal and saved me quite some headaches. So thank you for your awesome site :) If you ever feel the need to implement more features: A nice interactive area to sort pictures into a custom sprite with support for rotating sprites would be awesome. Especially the latter can be a hassle for non-square sprites. – Zerobinary99 Jul 20 '16 at 19:10
  • 1
    @greg But your generator does not reduce the amount of requests. Isn't that the point of sprites? – BitByBit Oct 09 '16 at 16:49
  • @BitByBit in src is passed empty transparent file. – Deykun Jan 02 '20 at 12:52
4

This is a simpler solution, check this

.my_picture{
    //target your sprite
    background: url(my_img.jpg) no-repeat;

    //Specify it full image
    backgound-size: 100%;

    //Position of the targeted picture
    background-position: left 0 bottom x%;

    //Zoom in or out on the position
    width: x%;

    //Scale height by playing with padding
    padding-bottom: x%;

    //Set height to 0 because of sprite size
    height: 0;
}

How does it work? To target any sprite pictures easily, we have to specify sprite size to original, “100%”. We will then target a picture position from corresponding bottom, with left 0.

Because the sprite size is set to max 100%, we have to disable height, and the only option to set height now, is to play with padding-bottom, in percentage too.

Your image is now fully responsive, just play with width values (in percentage), to zoom in or out, and that’s all, you have a fully responsive css sprite.

Original article on my blog here: http://creativcoders.wordpress.com/2014/05/05/css-responsive-sprites/

Edouard Kombo
  • 475
  • 6
  • 7
  • It's awesome that you have included code here. However you should also include why this works with your answer and not defer the OP to a link. You can certainly provide the link for reference, but the link may can become invalid if the linked page changes. – rayryeng May 05 '14 at 16:55
  • Sorry, i'm really new on Stackoverflow, consider this is a beginner mistake. I have edited my original post with full documentation that explains why it is working. If you can vote for this, it would be great :) – Edouard Kombo May 06 '14 at 21:03
  • @EdouardKombo Is there a way to make this works also for non-squared sprites? – Lorenzo Marcon Nov 28 '14 at 12:18
  • @EdouardKombo Excellent solution. It looked too simple to be useful, but it works. I don't understand how it works, but that's not important. It required a few adjustments to the x% values to get the sprite in the right place. It works with oblong sprites too. Saved me a lot of effort! Thank you. – BlackMagic Apr 20 '15 at 13:11
4

This is the best responsive example I have found to solve the problem of sprite!

Cross-browser, responsive resizing/stretching of CSS sprite images

This method does not rely on background-size, so it will work in older browsers.

Stretchy Sprites

  • This example uses an image that is 800 wide x 160 high. This image contains 6 equal size sprites (160x160 each).

  • If your sprite size is different all you need to change is the max-width property of .sprite to match the individual sprite width.

  • To set the visible sprite: Set the left value of .sprite to: 0 = 1st sprite -100% = 2nd sprite -200% = 3rd sprite etc... Easy!

  • If you want images to stretch larger than their natural size: Add the class .no-limit to .stretchy. This removes max-width:160px from .stretchy and add min-height:100% to .sprite Alternatively you could set a larger max-width using a px value, e.g. 300px.

  • The spacer image can be any size, as long as it is propotional to the dimensions of the individual sprites.

Andres Separ
  • 2,508
  • 1
  • 13
  • 14
2

You can use websites to find out the exact coordinates of your sprite. I personally use http://www.spritecow.com/

Ankur Aggarwal
  • 2,803
  • 3
  • 27
  • 47
0

I spent a lot of time looking for an answer on this matter, I came out with this solution, it works for me at least for now, is based on fixed pixel box-sizing, and horizontal sprites, will be a mess with percentage anyway because you will have to do the math for the pixel values for that percentage, and for random located sprites because you will have to find the random location of the sprite inside the image, too much math for a simple task I believe.

You need:

  • Know the image width (compass image-width($image))
  • The original pixel size and location of the sprite inside the image (Photoshop does the trick)
  • The size of the containing box proportional to the corresponding sprite you are intended to show
  • And of course the amount of stretch you want to apply to the specific sprite.

As a piece of advice, you will have to leave at least 1px of physical margin between each image because percentages produce not integer pixels, and you will end up with overlaping sprites!! ;)

Check it out and give me some feedback please:

//functions

//stretch by percentage
@function stretchImage($width, $height, $percentage) {

    $s_width: round( ($width * $percentage) / 100 );
    $s_height: round( ($height * $percentage) / 100 );

    @return ($s_width, $s_height);
}

//strip units
//(Eric M Suzanne) http://stackoverflow.com/questions/12328259/how-do-you-strip-the-unit-from-any-number-in-sass
@function strip-units($number) {
  @return $number / ($number * 0 + 1);
}

//replace in string
//(css tricks) http://css-tricks.com/snippets/sass/str-replace-function/
@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);

    @if $index {
        @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
    }

    @return $string;
}

//get unitless percentage
@function getPercentageFrom($valueA, $valueB) {

    $percentage: percentage(strip-units($valueA)/strip-units($valueB));

    @return ($percentage);
}


//now the magic

//we know the witdh of the image containing the sprites 
$image: url(http://www.cssguy4hire.com/codePenAssets/sprite_test.png);
$image_width: 965px;

//the amount of strech we want to aply
$stretchTo: 175;

//we know the current sprite measures we  going to set 
$sprite_width: 150px;
$sprite_height: 150px;
//left is 0 cuz is first sprite                
$sprite_left: 0%;                

//stretch sprite                            
$stretch: stretchImage($sprite_width, $sprite_height, $stretchTo);
$width: nth($stretch, 1);                
$height: nth($stretch, 2);                

//set background size and position          
$bkg-size: getPercentageFrom($image_width * ($stretchTo / 100), $width);

//default position 0
$bkg_left: $sprite_left;              


//compose the css
#image {
    margin: auto;
    width: $width;
    height: $height;
    position: relative;
    display: block;
    background: #00f00f $image $bkg_left 0 no-repeat;
    background-size: $bkg-size;
    border: 5px solid #cccccc;

    //we chage the sprite
    &.sprite_1 {

        //the amount of strech we want to aply
        $stretchTo: 250;

        //we know the current sprite measures we  going to set 
        //0 is te first sprite starting left to right
        $sprite_width: 250px;
        $sprite_height: 75px;
        $sprite_left: 150px;              

        //stretch sprite                            
        $stretch: stretchImage($sprite_width, $sprite_height, $stretchTo);
        $width: nth($stretch, 1);                
        $height: nth($stretch, 2);                

        //set background size        
        $bkg-size: getPercentageFrom($image_width * ($stretchTo / 100), $width);
        $bkg_left: percentage($sprite_left / ($image_width - $sprite_width) );

        //compose the css
        width: $width;
        height: $height;
        background-size: $bkg-size;
        background-position: $bkg_left 0;

    }

    &.sprite_2 {

        //the amount of strech we want to aply
        $stretchTo: 80;

        //we know the current sprite measures we going to set 
        $sprite_width: 140px;
        $sprite_height: 120px;
        $sprite_left: 400px;              

        //stretch sprite                            
        $stretch: stretchImage($sprite_width, $sprite_height, $stretchTo);
        $width: nth($stretch, 1);                
        $height: nth($stretch, 2);                

        //set background size        
        $bkg-size: getPercentageFrom($image_width * ($stretchTo / 100), $width);
        $bkg_left: percentage($sprite_left / ($image_width - $sprite_width) );

        //compose the css
        width: $width;
        height: $height;
        background-size: $bkg-size;
        background-position: $bkg_left 0;

    }

    &.sprite_3 {

        //the amount of strech we want to aply
        $stretchTo: 125;

        //we know the current sprite measures we going to set 
        $sprite_width: 290px;
        $sprite_height: 134px;
        $sprite_left: 540px;              

        //stretch sprite                            
        $stretch: stretchImage($sprite_width, $sprite_height, $stretchTo);
        $width: nth($stretch, 1);                
        $height: nth($stretch, 2);                

        //set background size        
        $bkg-size: getPercentageFrom($image_width * ($stretchTo / 100), $width);
        $bkg_left: percentage($sprite_left / ($image_width - $sprite_width) );

        //compose the css
        width: $width;
        height: $height;
        background-size: $bkg-size;
        background-position: $bkg_left 0;

    }

    &.sprite_4 {

        //the amount of strech we want to aply
        $stretchTo: 153;

        //we know the current sprite measures we going to set 
        $sprite_width: 135px;
        $sprite_height: 56px;
        $sprite_left: 830px;              

        //stretch sprite                            
        $stretch: stretchImage($sprite_width, $sprite_height, $stretchTo);
        $width: nth($stretch, 1);                
        $height: nth($stretch, 2);                

        //set background size        
        $bkg-size: getPercentageFrom($image_width * ($stretchTo / 100), $width);
        $bkg_left: percentage($sprite_left / ($image_width - $sprite_width) );

        //compose the css
        width: $width;
        height: $height;
        background-size: $bkg-size;
        background-position: $bkg_left 0;

    }

}

http://codepen.io/wolfitoXtreme/pen/BymKyP

David Guyon
  • 2,343
  • 1
  • 26
  • 38
0

My approach is similar to Greg's in that I wrote a tool to generate responsive css sprites. I however have taken it one step further and added a sorting algorithm so you can pack more images efficiently onto a png.

Here is the Responsive CSS Sprite Generator Tool: https://responsive-css.us/

eivers88
  • 5,821
  • 1
  • 31
  • 34
-1

From a large FE experience, I've developed responsive sprites framework that does not rely on background-image, but instead it uses "physical" image in a container that is scaled like original image/part of sprites. The problem with css bgd-img is calculating size and position and its often for css to "miss" pics possition for few pixels. Most of the browsers renders these values at 0.1px, but rounds it as well. So the precision is (about 1/2 of the px). This missmatch multiplies when you try to scale it (to make it responsive). - so dont be fooled by "responsive sprites" that rely on css background-image. They're just a bad and displaced display of sprites image you need. - The JavaScript (framework) is far more precisious - (1/100px), and its solid ground for responsive images - as you have 1/50 size to scale pics and not loose any pixel. I'm not advertising this, If anyone is interested - take a look at: responsive-sprites.com

Bambino Negro
  • 95
  • 1
  • 8