user3097405
user3097405

Reputation: 823

responsive sprites / percentages

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,

Upvotes: 28

Views: 30293

Answers (9)

Bambino Negro
Bambino Negro

Reputation: 115

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

Upvotes: -1

eivers88
eivers88

Reputation: 6247

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/

Upvotes: 0

ChillyPenguin
ChillyPenguin

Reputation: 1180

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!

Upvotes: 30

Greg
Greg

Reputation: 321578

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.

Upvotes: 16

vals
vals

Reputation: 64164

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%;

Upvotes: 19

wolfitoXtreme
wolfitoXtreme

Reputation: 111

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

Upvotes: 0

Andres Separ
Andres Separ

Reputation: 3394

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.

Upvotes: 4

Edouard Kombo
Edouard Kombo

Reputation: 503

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/

Upvotes: 5

Ankur Aggarwal
Ankur Aggarwal

Reputation: 3101

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

Upvotes: 2

Related Questions