How can I scale an image in a CSS sprite
Asked Answered
I

15

171

In this article, http://css-tricks.com/css-sprites/, it talks about how can I crop off a smaller image from 1 bigger image. Can you please tell me if it is possible/how I can crop off a smaller image and then scale the cropped off region before I lay it out?

Here is an example from that article:

A
{
  background-image: url(http://www.jaredhirsch.com/coolrunnings/public_images/3deb155981/spriteme1.png);
  background-position: -10px -56px;
}

I would like to know how can I scale that image after I crop it from from spriteme1.png

Here is the URL of the example: http://css-tricks.com/examples/CSS-Sprites/Example1After/

So I would like to know if I can make the icons next to Item1,2,3,4 smaller?

Inartificial answered 12/3, 2010 at 2:50 Comment(3)
As Stephen asked, is there something stopping you from rendering the images at the size you want them in the first place?Isham
I ended up on this page since I was searching for an answer for the same thing. In today's world with high definition retina displays it's customary to build an image twice the size than it needs to be and then use height/width values in <img> attributes or CSS styles to reduce it to half the height/width when displaying. This ensures crisp display on smartphones and tablets. But PNG sprites are great for caching and rendering quickly. It would be best not only use a sprite of a 2x images, but to then scale it to a size that makes it look crisp also.Julesjuley
As the original question never got an accepted answer and there is a pretty neat and backward compatible solution, I made a new Codepen Stretchy version, as the original website isn't online anymore and maaaaybe there are still some people out there that need a backward compatible solution. I've made the Pen with attribution of the original work/author.Marthamarthe
G
145

2021 Update: Background size is supported by most major browser but if your mobile browsers doesn't support it use zoom.

You could use background-size, as its supported by most browsers (but not all http://caniuse.com/#search=background-size)

background-size : 150% 150%;

Or

You can use a combo of zoom for webkit/blink/ie and transform:scale for Mozilla(-moz-) and old Opera(-o-) for cross-browser desktop & mobile

[class^="icon-"]{
    display: inline-block;
    background: url('../img/icons/icons.png') no-repeat;
    width: 64px;
    height: 51px;
    overflow: hidden;
    zoom:0.5;
    /* Mozilla support */
    -moz-transform:scale(0.5);
    -moz-transform-origin: 0 0;
}

.icon-big{
    zoom:0.60;
    /* Mozilla support */
    -moz-transform:scale(0.60);
    -moz-transform-origin: 0 0;
}

.icon-small{
    zoom:0.29;
    /*  Mozilla support */
    -moz-transform:scale(0.29);
    -moz-transform-origin: 0 0;
}
Gayden answered 18/4, 2013 at 10:52 Comment(7)
Works great in Chrome, works OK in FF, IE9/10. Produces desired effect for the most part.Namangan
Using (example) background-size: 15%; works perfect for sprites while keeping the correct aspect ratio. It's a simple solution to use with breakpoints on responsive sites.Coley
the background-size property did not work for my svg sprite with a fixed height and width, however scale did the trick.Amphiprostyle
For adding support to IE8, use the -ms-zoom attribute as a synonym for zoom in IE8 Standards mode. -ms-zoom: 0.7; See the link below for more details: msdn.microsoft.com/en-us/library/ms531189(v=vs.85).aspxZoography
2017 update: background-size is supported by all major browsers, including IE9+. caniuse.com/#search=background-sizeAdrianaadriane
In Chrome, the other properties didn't work for me, but zoom did the trick. ie attempting to scale using background-size.... made the background-image disappear...Pudens
Note! This will not work if your image is not proportional. background-size : 150% 150%; is NOT scaling both dimenssions 1.5 times. What you would actually need is to know total width of the image and multiply it 1.5 times. So background-size: {{ totalW * 1.5 }}px {{ totalH * 1.5 }}px;.Amalburga
G
32

When you use sprites, you are limited to the dimensions of the image in the sprite. The background-size CSS property, mentioned by Stephen, isn't widely supported yet and might cause problems with browsers like IE8 and below - and given their market share, this isn't a viable option.

Another way to solve the problem is to use two elements and scale the sprite by using it with an img tag, like this:

<div class="sprite-image"
     style="width:20px; height:20px; overflow:hidden; position:relative">
    <!-- set width/height proportionally, to scale the sprite image -->
    <img src="sprite.png" alt="icon"
         width="20" height="80"
         style="position:absolute; top: -20px; left: 0;" />
</div>

This way, the outer element (div.sprite-image) is cropping a 20x20px image from the img tag, which acts like a scaled background-image.

Gauffer answered 18/3, 2010 at 16:41 Comment(3)
Like cletus and Quentin statet here , this might not be the best approach. For me it's a dealbreaker - I need to assign src by css.Cosset
-1: You can't mix presentation elements with content/data. <img> should only be used if it is part of content. for design purposes, background images are a must.Bashaw
Best answer (a) works universally, (b) is comprehensible by humans, (c) is brief, ... (z) separates presentation from content.Antheridium
G
20

Try this: Stretchy Sprites - Cross-browser, responsive resizing/stretching of CSS sprite images

This method scales sprites 'responsively' so that the width/height adjust according to your browser window size. It doesn't use background-size as support for this in older browsers is non-existent.

CSS

.stretchy {display:block; float:left; position:relative; overflow:hidden; max-width:160px;}
.stretchy .spacer {width: 100%; height: auto;}
.stretchy .sprite {position:absolute; top:0; left:0; max-width:none; max-height:100%;}
.stretchy .sprite.s2 {left:-100%;}
.stretchy .sprite.s3 {left:-200%;}

HTML

<a class="stretchy" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
<a class="stretchy s2" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
<a class="stretchy s3" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
Guile answered 31/5, 2012 at 2:35 Comment(4)
The link doesn't really explain the theory here. You are using a div with overflow: hidden as a cropping area/window over top of using a scaled version of the sprite image. Which is why it doesn't use a background image at all. Just one layer over top of another as a mask.Mummery
does spacer must be an image or can a simple div be used instead?Trudy
Here is a CodePen example of this. It seems to work only for horizontal or vertical sprites. Not grids.Baresark
I made a new Codepen Stretchy version, as the original website isn't online anymore and maaaaybe there are still some people out there that need a backward compatible solution. I've made the Pen with attribution of the original work/authorMarthamarthe
R
17

transform: scale(); will make original element preserve its size.

I found the best option is to use vw. It's working like a charm:

https://jsfiddle.net/tomekmularczyk/6ebv9Lxw/1/

#div1,
#div2,
#div3 {
  background:url('//www.google.pl/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png') no-repeat;
  background-size: 50vw;   
  border: 1px solid black;
  margin-bottom: 40px;
}

#div1 {
  background-position: 0 0;
  width: 12.5vw;
  height: 13vw;
}
#div2 {
  background-position: -13vw -4vw;
  width: 17.5vw;
  height: 9vw;
  transform: scale(1.8);
}
#div3 {
  background-position: -30.5vw 0;
  width: 19.5vw;
  height: 17vw;
}
<div id="div1">
  </div>
  <div id="div2">
  </div>
  <div id="div3">
  </div>
Related answered 10/12, 2016 at 11:21 Comment(6)
Hello this doesn't reply the question. You should show the three divs with different scales of the same image. In few words, it should show different sizes of the "font". Can you fix it?Memorial
hi @Robert. How about now?Related
P.S. have you noticed behaviours using VW measure unit?Memorial
I'm not sure, what behaviors do you mean?Related
VW VH are scaling proportionally with viewport size. I have never used them until now. It is just a curiosity about your experience using them. Are they so "magic" or are there issues to consider (unexpected behaviours) in some situations you may have noticed? thank youMemorial
@Memorial I have used them on small project and they have worked well for me, but I believe like anything else it may have some drawbacks.Related
Z
12

This seems to work for me.

If the sprites are in grid, set the background-size to 100% number of sprites across and 100% number of sprites down. Then use background-position -<x*100>% -<y*100>% where x and y are the zero based sprite

In other words if you want the 3rd sprite from the left and 2nd row that's 2 over and 1 down so

background-position: -200% -100%;

For example here's a sprite sheet 4x2 sprites

enter image description here

And here's an example

div {
  margin: 3px;
  display: inline-block;
}
.sprite {
  background-image: url('https://i.stack.imgur.com/AEYNC.png');
  background-size: 400% 200%;  /* 4x2 sprites so 400% 200% */
}
.s0x0 { background-position:    -0%   -0%; }
.s1x0 { background-position:  -100%   -0%; }
.s2x0 { background-position:  -200%   -0%; }
.s3x0 { background-position:  -300%   -0%; }
.s0x1 { background-position:    -0%  -100%; }
.s1x1 { background-position:  -100%  -100%; }
.s2x1 { background-position:  -200%  -100%; }
.s3x1 { background-position:  -300%  -100%; }
<div class="sprite s3x1" style="width: 45px; height:20px"></div>
<div class="sprite s3x1" style="width: 128px; height:30px"></div>
<div class="sprite s3x1" style="width: 64px; height:56px"></div>
<div class="sprite s2x1" style="width: 57px; height:60px"></div>
<div class="sprite s3x0" style="width: 45px; height:45px"></div>
<div class="sprite s0x1" style="width: 12px; height:100px"></div>

<br/>
<div class="sprite s0x0" style="width: 45px; height:20px"></div>
<div class="sprite s1x0" style="width: 128px; height:45px"></div>
<div class="sprite s2x0" style="width: 64px; height:56px"></div>
<div class="sprite s3x0" style="width: 57px; height:60px"></div>
<br/>
<div class="sprite s0x1" style="width: 45px; height:45px"></div>
<div class="sprite s1x1" style="width: 12px; height:50px"></div>
<div class="sprite s2x1" style="width: 12px; height:50px"></div>
<div class="sprite s3x1" style="width: 12px; height:50px"></div>

If the sprites are different sizes you'd need to set the background-size for each sprite to the a percent such that that sprite's width becomes 100%

In other words if image is 640px wide and the sprite inside that image is 45px wide then to get that 45px to be 640px

xScale = imageWidth / spriteWidth
xScale = 640 / 45
xScale = 14.2222222222
xPercent = xScale * 100
xPercent = 1422.22222222%

Then you need to set the offset. The complication of the offset is that 0% is aligned left and 100% is aligned right.

enter image description here

As a graphics programmer, I'd expect an offset of 100% to move the background 100% across the element, in other words entirely off the right side but that's not what 100% means when used with backgrouhnd-position. background-position: 100%; means right aligned. So, the forumla for taking that into account after scaling is

xOffsetScale = 1 + 1 / (xScale - 1)              
xOffset = offsetX * offsetScale / imageWidth

Assume the offset is 31px

xOffsetScale = 1 + 1 / (14.222222222 - 1)
xOffsetScale = 1.0756302521021115
xOffset = offsetX * xOffsetScale / imageWidth
xOffset = 31 * 1.0756302521021115 / 640
xOffset = 0.05210084033619603
xOffsetPercent = 5.210084033619603

Here's a 640x480 image with 2 sprites.

  1. at 31x 27y size 45w 32h
  2. at 500x 370y size 105w 65h

enter image description here

Following the math above for sprite 1

xScale = imageWidth / spriteWidth
xScale = 640 / 45
xScale = 14.2222222222
xPercent = xScale * 100
xPercent = 1422.22222222%

xOffsetScale = 1 + 1 / (14.222222222 - 1)
xOffsetScale = 1.0756302521021115
xOffset = offsetX * xOffsetScale / imageWidth
xOffset = 31 * 1.0756302521021115 / 640
xOffset = 0.05210084033619603
xOffsetPercent = 5.210084033619603

yScale = imageHeight / spriteHEight
yScale = 480 / 32
yScale = 15
yPercent = yScale * 100
yPercent = 1500%

yOffsetScale = 1 + 1 / (15 - 1)
yOffsetScale = 1.0714285714285714
yOffset = offsetY * yOffsetScale / imageHeight
yOffset = 27 * 1.0714285714285714 / 480
yOffset = 0.06026785714285714
yOffsetPercent = 6.026785714285714

div {
  margin: 3px;
  display: inline-block;
}
.sprite {
  background-image: url('https://i.stack.imgur.com/mv9lJ.png');
}
.s1 {
  background-size:      1422.2222% 1500%;
  background-position:  5.210084033619603% 6.026785714285714%;
}
.s2 {
  background-size:      609.5238095238095% 738.4615384615385%;
  background-position:  93.45794392523367% 89.1566265060241%;
}
<div class="sprite s1" style="width: 45px; height:20px"></div>
<div class="sprite s1" style="width: 128px; height:30px"></div>
<div class="sprite s1" style="width: 64px; height:56px"></div>
<div class="sprite s1" style="width: 57px; height:60px"></div>
<div class="sprite s1" style="width: 45px; height:45px"></div>
<div class="sprite s1" style="width: 12px; height:50px"></div>
<div class="sprite s1" style="width: 50px; height:40px"></div>
<hr/>
<div class="sprite s2" style="width: 45px; height:20px"></div>
<div class="sprite s2" style="width: 128px; height:30px"></div>
<div class="sprite s2" style="width: 64px; height:56px"></div>
<div class="sprite s2" style="width: 57px; height:60px"></div>
<div class="sprite s2" style="width: 45px; height:45px"></div>
<div class="sprite s2" style="width: 12px; height:50px"></div>
<div class="sprite s2" style="width: 50px; height:40px"></div>
Zipporah answered 19/6, 2019 at 9:43 Comment(2)
How did you calculate the values for offsetX and offsetY?Irbm
Simplified: xOffsetPercent = 100 * offsetX / (imageWidth - spriteWidth). @Irbm offsetX is the offset x in pixels to the sprite in the sprite sheet.Wolffish
M
7

Here's what I did to do this. Keep in mind it won't work on IE8 and below.

#element {
  width:100%;
  height:50px;
  background:url(/path/to/image.png);
  background-position:140.112201963534% 973.333333333333%;
}

The background image's width will scale down as the parent of #element scales down. You can do the same with its height, too, if you convert height to a percentage. The only tricky bit are figuring out the percentages for background-position.

The first percentage is the width of the targeted area of the sprite when at normal width divided by the sprite's total width, and multiplied by 100.

The second percentage is the height of the targeted area of the sprite before being scaled divided by the sprite's total height, and multiplied by 100.

The wording on those two equations is a little sloppy, so let me know if you need me to explain it better.

Mckim answered 7/10, 2011 at 13:43 Comment(0)
C
5

Old post, but here's what I did using background-size:cover; (hat tip to @Ceylan Pamir)...

EXAMPLE USAGE
Horizontal circle flipper (hover on front side image, flips to back with different image).

EXAMPLE SPRITE
480px x 240px

EXAMPLE FINAL SIZE
Single image @ 120px x 120px

GENERIC CODE
.front {width:120px; height:120px; background:url(http://www.example.com/images/image_240x240.png); background-size:cover; background-repeat:no-repeat; background-position:0px 0px;}

.back {width:120px; height:120px; background:url(http://www.example.com/images/image_240x240.png); background-size:cover; background-repeat:no-repeat; background-position:-120px 0px;}

ABBREVIATED CASE FIDDLE
http://jsfiddle.net/zuhloobie/133esq63/2/

Cubicle answered 1/5, 2015 at 18:18 Comment(0)
B
4

try using background size: http://webdesign.about.com/od/styleproperties/p/blspbgsize.htm

is there something stopping you from rendering the images at the size you want them in the first place?

Bolide answered 12/3, 2010 at 3:32 Comment(3)
Can I use JavaScript and CSS in combination to solve this? I tried the background-size; property. I can't get it work. It does not scale the image for some reason.Inartificial
background-size is CSS 3 and not widely supported yet.Ruthenic
Its supported by most browser versions now. Check this caniuse.com/#search=background-sizeAltdorfer
S
4

It took me a while to create a solution to this problem I was happy with:

Problem:

  • An SVG sprite of icons - say 80px x 3200px

  • We want to scale each use of them in content selectors (:before/:after) in various places over various sizes without re-defining the co-ords of each sprite based on the size used.

So this solution allows you to use the same sprite co-ords in a <button> as a <menuitem> whilst still scaling it.

[data-command]::before {
    content: '';
    position: absolute;
    background-image: url("images/sprite.svgz");
    background-repeat: no-repeat;
    background-size: cover;
}

button[data-command]::before {
  width: 32px;
  height: 32px;
}

menuitem[data-command]::before {
  width: 24px;
  height: 24px;
}

[data-command="cancel"]::before {
  background-position: 0% 35%;
}

[data-command="logoff"]::before {
  background-position: 0% 37.5%;
}

By using percentages (to 2 decimal places) in background-position rather than background-size as suggested by others here, you can scale the same icon declaration to any size, without needing to redeclare it.

The position-y percentage is the original sprite height/icon height as a % - in our case here 80px*100/3200px == each sprite is represented by a y-position of 2.5%.

If you have hover/mouseover states you can double the width of the sprite and specify in the position-x coordinate.

The disadvantage of this approach is that adding more icons at a later date will change the sprite height and so y-position %, but if you don't do that then your sprite co-ordinates will need change for each scaled resolution you require.

Sexology answered 3/8, 2016 at 15:29 Comment(0)
L
3

Use transform: scale(...); and add matching margin: -...px to compensate free space from scaling. (you can use * {outline: 1px solid}to see element boundaries).

Lamellate answered 5/2, 2018 at 15:39 Comment(0)
U
2

Well I think found a simpler solution for scaling images : example - lets say there is an image with 3 equal sized sprites which you would want to use, use CSS to scale the image

background-size : 300% 100%;

and then specify the custom height and width that needs to be applied to your html element eg:

 width :45%;
 height:100px;

A sample code would look something like this :

.customclass {
    background: url("/sample/whatever.png") 0 0 no-repeat ;
    background-size : 300% 100%;
    width :45%;
    height:100px;
}

im pretty new to css ,and styling is not my best area this could be a wrong way of doing it.. but it worked for me in Firefox/Chrome/Explorer 10 ,hope it works in older versions too..

Urbanist answered 14/10, 2013 at 16:32 Comment(0)
E
2

2018 here. Use background-size with percentage.

SHEET:

This assumes a single row of sprites. The width of your sheet should be a number that is evenly divisible by 100 + width of one sprite. If you have 30 sprites that are 108x108 px, then add extra blank space to the end to make the final width 5508px (50*108 + 108).

CSS:

.icon{
    height: 30px;  /* Set this to anything. It will scale. */
    width: 30px; /* Match height. This assumes square sprites. */
    background:url(<mysheeturl>);
    background-size: 5100% 100%; /*  5100% because 51 sprites. */
}

/* Each image increases by 2% because we used 50+1 sprites. 
   If we had used 20+1 sprites then % increase would be 5%. */

.first_image{
    background-position: 0% 0;
}

.ninth_image{
    background-position: 16% 0; /* (9-1) x 2 = 16 */
}

HTML:

<div class ="icon first_image"></div>
<div class ="icon ninth_image"></div>
Ebner answered 6/10, 2018 at 16:29 Comment(0)
T
2

Use transform: scale(0.8); with the value you need instead of 0.8

Tetrastichous answered 5/9, 2019 at 2:12 Comment(0)
S
-1

Set the width and height to wrapper element of the sprite image. Use this css.

{
    background-size: cover;
}
Strohl answered 13/10, 2014 at 15:15 Comment(3)
I don't understand why this is down-voted. Worked for me. Will post my method as an answer.Cubicle
I agree with chris here. This solves the problem in my case too. Not sure why it's downvoted!Hove
It doesn't work with sprite (look at question title), that's why this solution is downvoted.Maharashtra
S
-8

Easy... Using two copies of same image with different scale on the sprite's sheet. Set the Coords and size on the app's logic.

Sammy answered 23/6, 2015 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.