What's the Math Behind CSS's Background-Size:Cover

What's the math behind CSS's background-size:cover

Here's a logic behind cover calculations.

You have four base values :

imgWidth // your original img width
imgHeight

containerWidth // your container width (here 698px)
containerHeight

Two ratios derived from these values :

imgRatio = (imgHeight / imgWidth)       // original img ratio
containerRatio = (containerHeight / containerWidth) // container ratio

You want to find two new values :

finalWidth // the scaled img width
finalHeight

So :

if (containerRatio > imgRatio) 
{
finalHeight = containerHeight
finalWidth = (containerHeight / imgRatio)
}
else
{
finalWidth = containerWidth
finalHeight = (containerWidth / imgRatio)
}

... and you have the equivalent of a background-size : cover.

Background Size: Contain, get Size after scale

CSS property background-size: contain; scales the image to the largest so that both the height and width will fit inside, retaining the same aspect ratio of course.

Just like @Teemu said, A background image is a kinda pseudo element which you actually can't refer. But I can show you a workaround on how to get the real image size and compute the scaled background-image size.

It works like ratio and proportion where:

real_image_width is to real_image_height as resized_image_width is to resized_image_height

First we need to get the real size of the image:

var img = new Image;
img.src = $('#imageButton').css('background-image').replace(/url\(|\)$/ig, "");
var imgW = img.width;
var imgH = img.height;

Then, compare which dimension is the largest and calculate the proportion:

var newW, newH;

if(imgW > imgH){
newW = $('#imageButton').width(); //100;
newH = imgH / imgW * newW;
}else{
newH = $('#imageButton').height(); //100
newW = imgW / imgH * newH;
}

console.log(newW+':'+newH);

If the image is not yet loaded or cached it will return a size of 0, a good way to fix this is to get the size when the image is has been loaded using .load() function.

Browsers also differ in sub-pixel rendering, I think you need to round off to nearest .5 decimal to get the exact safest value (43.7832 => 43.5). Using: (Math.round(value * 2) / 2).toFixed(1)

That's it! Here is the sample fiddle.

How to get the scale percentage of an image when using background-size:cover?

If we suppose your image has a dimension of WxH and the screen size is AxB then it should be the biggest value between A/W and B/H.

Some examples:

.box {  width:400px;  height:200px;  background:url(https://picsum.photos/300/300?image=0) center/cover;}/*we will have 1.333 = 400/300 and 0.6667 = 200/300*/img { transform:scale(1.3333); transform-origin:top left;}
<div class="box">
</div><img src="https://picsum.photos/300/300?image=0">

How to get the current, real , background image size, when background-size is cover?

I found the solution by myself. Here is a nice jsfiddle visualization, where we calculate the container size and the actual background image size separately.

You can resize the image container (red border) by dragging it from the bottom right corner and see how the container size changes separately from the actual background size: https://jsfiddle.net/ahvonenj/o76k5jbx/

$(document).ready(function()
{
var fullhdWidth = 1920;
var fullhdHeight = 1080;
var fullhdRatio = fullhdWidth / fullhdHeight; // About 1.7

$('#wrapper').resize(function()
{
var containerWidth = $(this).width();
var containerHeight = $(this).height();
var containerRatio = containerWidth / containerHeight;
var realWidth = null;
var realHeight = null;

console.log(containerWidth, containerHeight, containerRatio);

if(containerRatio > fullhdRatio)
{
realWidth = containerWidth;
realHeight = containerWidth/fullhdRatio;
}
else
{
realWidth = containerHeight*fullhdRatio;
realHeight = containerHeight;
}
});
});

Note: I am using this small library to detect size changes on the container div element, as jQuery's resize handler can only be bound to window object.

CSS background-size: cover + background-attachment: fixed clipping background images

Unfortunately this is simply an artifact of how fixed positioning works in CSS and there is no way around it in pure CSS - you have to use Javascript.

The reason this happens is due to the combination of background-attachment: fixed and background-size: cover. When you specify background-attachment: fixed it essentially causes the background-image to behave as if it were a position: fixed image, meaning that it's taken out of the page flow and positioning context and becomes relative to the viewport rather than the element it's the background image of.

So whenever you use these properties together, the cover value is being calculated relative to the size of the viewport irrespective of the size of the element itself, which is why it works as expected when the element is the same size as the viewport but is cropped in unexpected ways when the element is smaller than the viewport.

To get around this you basically need to use background-attachment: scroll and bind an event listener to the scroll event in JS that manually updates the background-position relative to how far the window has been scrolled in order to simulate fixed positioning but still calculate background-size: cover relative to the container element rather than the viewport.

CSS background-size: cover and background positioning for a 1000x100 graphic

Rather than background-size: cover; try background-size: 100% auto; to base it off the width of it's container and not the height. It still follow it's aspect ration but doesn't worry about the height anymore.

background-size: cover; doesn't actually stretch the image?

Try background-size: 100% 100%; instead of cover.

cover will cause the background image to be scaled so that it fills the block dimensions,
cropping any excess width or height depending on the miss-match between the aspect ratio of
the background image and the block to which the image is applied.

body {    margin:0;}.carnival {    background: url(http://placekitten.com/700/1400) no-repeat;    background-size: 100% 100%;    height: 100%;    left: 0;    right: 0;    position: absolute;}
<div class="carnival"></div>


Related Topics



Leave a reply



Submit