9

is there an easy way to get the final height and width of a background image with Javascript or jQuery even if a background-size property was applied?

I mean, I know I can get the background image url and load it to an Image object and then get the width and height. But it is the size of the source image. If someone scaled it with CSS then the size changed

How can I find its final size?

@edit

it is different from the question marked as similar because it doesnt say how to get the size in pixels if someone changed the background-size

Victor Ferreira
  • 6,151
  • 13
  • 64
  • 120
  • Woudn't this work for you? document.getElementById("myImage").style.offsetHeight; document.getElementById("myImage").style.offsetWidth; – Anupam Saini May 02 '15 at 07:20
  • this will return the size of the element, not the size of the background-image, and there are no property `offsetHeight` and `offsetWidth` in style. it's height and width. if im not mistekn they are only returned if you applied them by css before. and offsetWidth and offsetHeight returns the element size, and not the background image's – Victor Ferreira May 02 '15 at 07:24
  • 1
    The only thing I can think of is reading the `$("img").css("background-size")` property and parsing it. It can only be `cover // Element width`, `contain // largest image dimension` or a static value (*px, em or %*). – CodingIntrigue May 02 '15 at 07:34
  • i think i'll have to calculate it then. check if it's % and apply the percentage to the element size, if it's contain or cover, check what dimension is the smaller or bigger, and pray to 'em', 'rem' 'vh' etc, if applied (i'm not sure if they are), will be automatically converted to pixels (notice that some things in css are converted, for example, background-position, if you use 'em' at least chrome convert it to pixels) – Victor Ferreira May 02 '15 at 07:37
  • possible duplicate of [How do I get background image size in jQuery?](http://stackoverflow.com/questions/5106243/how-do-i-get-background-image-size-in-jquery) – davidcondrey May 02 '15 at 07:50
  • i read it but it doesnt answer the question as expected. it doesn't say how to get the size in pixels if someone changed the `background-size` rule – Victor Ferreira May 02 '15 at 07:54

2 Answers2

17

Using getComputedStyle, I've created this script that returns the width and height of a given element's background, in pixels. It works with:

  • Dimensions (width or height) set to auto, either explicitly or because no specific value was given (width and height default to auto)
  • Dimensions set to percentage %
  • Dimensions set to pixels px
  • Dimensions set to a combination of any of the previous. (i.e width: 100px; height: auto or width: auto; height: 32.4% or height: 100px; width: 2% or width: 21.2%)
  • background-size set to cover or contain

It works if background-size is set with an external CSS file, inline CSS, inline header CSS or if it is not set at all (meaning width and height are auto).

Here's a JsFiddle (with cover example)

http://jsfiddle.net/gp4e9d3z/3/

And here's StackOverflow's code snippet (with percentage auto units)

function getBackgroundSize(elem) {
    // This:
    //       * Gets elem computed styles:
    //             - CSS background-size
    //             - element's width and height
    //       * Extracts background URL
    var computedStyle = getComputedStyle(elem),
        image = new Image(),
        src = computedStyle.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, '$2'),
        cssSize = computedStyle.backgroundSize,
        elemW = parseInt(computedStyle.width.replace('px', ''), 10),
        elemH = parseInt(computedStyle.height.replace('px', ''), 10),
        elemDim = [elemW, elemH],
        computedDim = [],
        ratio;
    // Load the image with the extracted URL.
    // Should be in cache already.
    image.src = src;
    // Determine the 'ratio'
    ratio = image.width > image.height ? image.width / image.height : image.height / image.width;
    // Split background-size properties into array
    cssSize = cssSize.split(' ');
    // First property is width. It is always set to something.
    computedDim[0] = cssSize[0];
    // If height not set, set it to auto
    computedDim[1] = cssSize.length > 1 ? cssSize[1] : 'auto';
    if(cssSize[0] === 'cover') {
        // Width is greater than height
        if(elemDim[0] > elemDim[1]) {
            // Elem's ratio greater than or equal to img ratio
            if(elemDim[0] / elemDim[1] >= ratio) {
                computedDim[0] = elemDim[0];
                computedDim[1] = 'auto';
            } else {
                computedDim[0] = 'auto';
                computedDim[1] = elemDim[1];
            }
        } else {
            computedDim[0] = 'auto';
            computedDim[1] = elemDim[1];
        }
    } else if(cssSize[0] === 'contain') {
        // Width is less than height
        if(elemDim[0] < elemDim[1]) {
            computedDim[0] = elemDim[0];
            computedDim[1] = 'auto';
        } else {
            // elem's ratio is greater than or equal to img ratio
            if(elemDim[0] / elemDim[1] >= ratio) {
                computedDim[0] = 'auto';
                computedDim[1] = elemDim[1];
            } else {
                computedDim[1] = 'auto';
                computedDim[0] = elemDim[0];
            }
        }
    } else {
        // If not 'cover' or 'contain', loop through the values
        for(var i = cssSize.length; i--;) {
            // Check if values are in pixels or in percentage
            if (cssSize[i].indexOf('px') > -1) {
                // If in pixels, just remove the 'px' to get the value
                computedDim[i] = cssSize[i].replace('px', '');
            } else if (cssSize[i].indexOf('%') > -1) {
                // If percentage, get percentage of elem's dimension
                // and assign it to the computed dimension
                computedDim[i] = elemDim[i] * (cssSize[i].replace('%', '') / 100);
            }
        }
    }
    // If both values are set to auto, return image's 
    // original width and height
    if(computedDim[0] === 'auto' && computedDim[1] === 'auto') {
        computedDim[0] = image.width;
        computedDim[1] = image.height;
    } else {
        // Depending on whether width or height is auto,
        // calculate the value in pixels of auto.
        // ratio in here is just getting proportions.
        ratio = computedDim[0] === 'auto' ? image.height / computedDim[1] : image.width / computedDim[0];
        computedDim[0] = computedDim[0] === 'auto' ? image.width / ratio : computedDim[0];
        computedDim[1] = computedDim[1] === 'auto' ? image.height / ratio : computedDim[1];
    }
    // Finally, return an object with the width and height of the
    // background image.
    return {
        width: computedDim[0],
        height: computedDim[1]
    };
}

// Stuff for debugging

function updateData() {
    var background = getBackgroundSize(document.body);
    document.getElementById('width').innerHTML = background.width + 'px';
    document.getElementById('height').innerHTML = background.height + 'px';
    document.getElementById('winWidth').innerHTML = getComputedStyle(document.body).width;
    document.getElementById('winHeight').innerHTML = getComputedStyle(document.body).height;
}
// Execute onload, so that the background image is already loaded.
window.onload = window.onresize = updateData;
html, body {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}
body {
    background: url('http://hdwallpapersfit.com/wp-content/uploads/2015/03/images-7.jpg');
    background-size: 80% auto;
}
div {
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
}
<div id="data">
    Background width: <span id="width"></span>
    <br>
    Background height: <span id="height"></span>
    <hr>
    Body width: <span id="winWidth"></span>
    <br>
    Body height: <span id="winHeight"></span>
</div>
1

Using the JSFiddle Here, I found that changing the height or width of the container forces the image to be scaled to the largest height or width. Meaning that the measurement of one edge of the background will be equal to one of the dimension of the container. Using this and some proportions we can calculate the dimensions of the image.

// let .container  represent element containing the image
var image; // the image object to the background image
var dim_h, dim_w; // the height and width of the actual image


height = $(".container").height();
width = $(".container").width();

if (height >= width)
{
  dim_h = height;
  dim_w = (height / image.height) * image.width;
}
else
{
  dim_w = width;
  dim_h = (width / image.width) * image.height;
}

// dim_w and dim_h contain the width and height of the actual 
// background image after scaling

The above code uses the proportion below to calculate it.

(element_height / image_height) == (element_width / image_width)

I think it should give you the answer you want.

Zara Kay
  • 164
  • 1
  • 8
  • i want the background image – Victor Ferreira May 02 '15 at 07:24
  • Wouldn't the size of the background image be the size of the element in is contained in? – Zara Kay May 02 '15 at 07:29
  • what if I use `background-size: cover` for example? won't it change the size of the backgrund image? – Victor Ferreira May 02 '15 at 07:30
  • According to the w3c website [here](http://www.w3schools.com/cssref/css3_pr_background-size.asp). From what I understand, if you use `cover` the background is scaled to fit the background area for the element, so it should be equal to the size of the element it is contained in. – Zara Kay May 02 '15 at 07:32
  • it says: "Scale the background image to be as large as possible so that the background area is completely covered by the background image. **Some parts of the background image may not be in view within the background positioning area**" so this part that is not visible is outside the box, then it's bigger than the box, so it's not the same size – Victor Ferreira May 02 '15 at 07:34
  • 1
    @MigaraLiyanagamage not related but be carefull, w3school is not w3c – Kaiido May 02 '15 at 09:19