Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is background-size percentage calculated?

I have a sprite that I am using and I wanted to reuse one of the images in the sprite but at half the size so I thought if I just used background-size:50%;, it would resize the background by 50%, but it seemed to quarter the size for some reason:

.test {
  background: url(https://i.stack.imgur.com/KaIav.png) left top no-repeat;
  width: 112px;
  height: 112px;
  border: 1px solid red;
}

.test.half-size {
  width: 56px;
  height: 56px;
  background-size: 50%;
}
<div class="test"></div>
<div class="test half-size"></div>

Now I can fix this by having the background size as 113%:

.test {
  background: url(https://i.stack.imgur.com/KaIav.png) left top no-repeat;
  width: 112px;
  height: 112px;
  border: 1px solid red;
}

.test.half-size {
  width: 56px;
  height: 56px;
  background-size: 113%;
}
<div class="test"></div>
<div class="test half-size"></div>

But why is the background-size greater than 100% when the image is smaller than the original?

Is there a set calculation I can apply when figuring out how to resize the sprite?

like image 756
Pete Avatar asked Feb 28 '17 14:02

Pete


2 Answers

As per the W3C Specs:

A percentage is relative to the background positioning area.

and background positioning area is one of either border-box or padding-box or content-box based on the background-origin property. Here you haven't specified any value explicitly for this and so its default value of padding-box is used. This element has no padding and so it's equal to content-box.


Your image is 126 x 112 px but width and height of the element is 56 x 56px, so a background-size: 100% (which is inferred as100% auto) would mean the image is scaled down till it has a width of 56px. Now to get to 56px, the width is scaled down by 44.44% of the image's original size. So, to preserve aspect ratio (as one value is auto), the height of the image is also scaled down to 44.44%, which is, 49.78px (or 50px approximately). As you can see the calculated background image's dimensions are 56px x 50px (and not 56px x 56px) and so it doesn't cover the box entirely. You can see this clearly in the below snippet.

.test {
  background: url(https://i.stack.imgur.com/KaIav.png) left top no-repeat;
  width: 56px;
  height: 56px;
  border: 1px solid red;
  background-size: 56px 50px; /* see how this is same as 100% or 100% auto */
}

.test.t2 {
  width: 56px;
  height: 56px;
  background-size: 100%;
}

.test.t3 {
  width: 56px;
  height: 56px;
  background-size: 100% auto;
}
<div class="test"></div>
<div class="test t2"></div>
<div class="test t3"></div>

Note: The 56px width includes the white-spaces on the right side of the circle and so even though it covers the entire width of the element, you will still see a gap. This is due to the image itself having a space.


Now when you set background-size: 50% ( = 50% auto), it would mean the max width of the image can be 28px and so it is scaled down by 22.22%. This means the height is also scaled down 22.22%, which is, roughly 25px. This is why you see it as being almost quarter size (but not exactly quarter). This can again be seen visually in the below snippet:

.test {
  background: url(https://i.stack.imgur.com/KaIav.png) left top no-repeat;
  width: 56px;
  height: 56px;
  border: 1px solid red;
  background-size: 28px 25px; /* again see how they are same */
}

.test.t2 {
  width: 56px;
  height: 56px;
  background-size: 50%;
}

.test.t3 {
  width: 56px;
  height: 56px;
  background-size: 50% auto;
}
<div class="test"></div>
<div class="test t2"></div>
<div class="test t3"></div>

When we set background-size: 113%, it means the the width can be max 113% of the container's width, which would be, 63.28px and this is roughly 50% of the original image's width. Since width is scaled down by 50% from the original image, its height is also scaled down by same amount and so the resulting value is 56px (which is nothing but the height of the element and so it covers the box vertically). Now, since you've also given the background-position as left-top, the image is placed with respect to the left edge of the container and so the white-space which is present on the right side of the image (the other 7.28px) is invisible as the box will not show anything more than its width.

You've already answered the second part of your question and so I'm not going over it again.


For Future Readers: For OP's case, it might not be possible to get rid of the white-spaces because it is part of a sprite but if your case is different and you can get rid of the spaces then that is the best.

If the white-spaces on the right side are removed and the image is cropped to its actual size (which is, 112 x 112px) then just setting background-size: 100% 100% (or even 100% auto) would be enough. The container element's dimensions when set as half or quarter (or whatever) size of the original will automatically do the scaling for us.

.test {
  background: url(https://i.stack.imgur.com/UaCct.png) left top no-repeat;
  width: 112px;
  height: 112px;
  background-size: 100% 100%;
  border: 1px solid red;
}

.test.half-size {
  width: 56px;
  height: 56px;
}

.test.quarter-size {
  width: 28px;
  height: 28px;
}
<div class="test"></div>
<div class="test half-size"></div>
<div class="test quarter-size"></div>
like image 69
Harry Avatar answered Sep 28 '22 09:09

Harry


After a lot of playing around with the sprite I have come to the conclusion that it is width of full sprite divided by width of sprite part and times it by 100 will give you the x-axis background size percentage and then do the same with height for the y-axis background size.

So in my case to get the x percentage, it was

(         126px         /         112px        ) * 100 = 112.5% 
  Full width of sprite     width of sprite part

and to get the y percentage it was

(         112px         /         112px        ) * 100 = 100% 
 Full height of sprite     height of sprite part

This means that a background-size: 112.5% 100% will work for any square div with that sprite:

.test {
  background: url(https://i.stack.imgur.com/KaIav.png) left top no-repeat;
  width: 112px;
  height: 112px;
  background-size: 112.5% 100%;
  border: 1px solid red;
}

.test.half-size {
  width: 56px;
  height: 56px;
}
.test.random-size {
  width: 90px;
  height: 90px;
}
<div class="test"></div>
<div class="test half-size"></div>
<div class="test random-size"></div>
like image 30
Pete Avatar answered Sep 28 '22 10:09

Pete