32

Covering the browser's viewport with a 400x200 background image using background-size:cover:

html, body {height:100%;}
body {background:url("http://lorempixel.com/g/400/200/") center no-repeat; background-size:cover;}

I'd like to retrieve - through javascript - the computed background-size value that is applied to the picture, for example 1536px 768px

Live demo : https://codepen.io/abernier/pen/rHkEv

NB: I just want to read it, at no time compute it (since the browser already has, in a way)

abernier
  • 27,030
  • 20
  • 83
  • 114
  • 1
    Well that's an intelligent question, I am afraid there might be no way to do what you are trying to achieve! Upvoting for potential. – Ahmad Alfy Jan 19 '14 at 11:58
  • 1
    I don't think there's an API to retrieve that factor. – Bergi Jan 21 '14 at 23:44
  • 2
    I think he already knows how to compute it but was curious to know if it would be possible to get the number the browser computed. – Mixthos Jan 22 '14 at 00:06
  • 1
    BTW: I don't think there is a way to get to that number. – Mixthos Jan 22 '14 at 00:06
  • @ErikE: "Do you order your fast food hamburger patties cooked on the north side before the south side, and reject those that are cooked in the wrong order?" lol, really :) – abernier Jan 22 '14 at 00:15
  • just had a try with: `window.getComputedStyle(document.body).backgroundSize` but returns `"cover"` :/ ... – abernier Jan 22 '14 at 00:22
  • 2
    I know you can use `window.devicePixelRatio` to get the pixel ratio for the screen itself, I wonder if something similar exists for a specific DOM element? – Dryden Long Jan 22 '14 at 00:27
  • Actually, images are not zoomed, they are simply resized... – Mr. Alien Jan 23 '14 at 11:10
  • @Mr.Alien well, "resized" if you prefer that word ;) – abernier Jan 23 '14 at 17:22

8 Answers8

11

I know I'm very late to the party but i have used the code below to solve this.

    var backgroundImage = new Image();
    backgroundImage.src = $('my_div_id').css('background-image').replace(/"/g,"").replace(/url\(|\)$/ig, "");

    backgroundImage.onload = function() {
        var width = this.width;
        var height = this.height;

        var object = $('#my_div_id');

        /* Step 1 - Get the ratio of the div + the image */
        var imageRatio = width/height;
        var coverRatio = object.outerWidth()/object.outerHeight();

        /* Step 2 - Work out which ratio is greater */
        if (imageRatio >= coverRatio) {
            /* The Height is our constant */
            var coverHeight = object.outerHeight();
            var scale = (coverHeight / height);
            var coverWidth = width * scale;
        } else {
            /* The Width is our constant */
            var coverWidth = object.outerWidth();
            var scale = (coverWidth / width);
            var coverHeight = height * scale;
        }
        var cover = coverWidth + 'px ' + coverHeight + 'px';
        alert('scale: ' + scale + ', width: ' + coverWidth + ', height: ' + coverHeight + ', cover property: ' + cover);
    };

A detailed walkthrough can be found here http://www.gene.co.uk/get-computed-dimensions-background-image-background-size-cover/

Hob
  • 153
  • 1
  • 6
  • I have upvoted, because truly consider this answer as the best matching the question. Solution tested – works well. Just link is broken, but that is minor. – Nik Sumeiko May 10 '15 at 07:21
  • Live link — http://www.gene.co.uk/blog/get-computed-dimensions-background-image-background-size-cover/ – christian.thomas Jun 03 '15 at 17:15
  • Just over a year later and this is the best answer to this problem on the entire internet. – Adam Oct 21 '15 at 22:29
5

You can use Image object to get dimensions of your background image file, then compare it against size of the element

var element = ...

var img = new Image()
img.onload = compare;
img.src = 'path/to/your/background-image'

function compare() {
  var fx = element.offsetWidth/img.width;
  var fy = element.offsetHeight/img.height;
  console.log(fx, fy);
}

Then depending on value of background-size property you can get exact scale factors

function compare() {
  var fx = element.offsetWidth/img.width;
  var fy = element.offsetHeight/img.height;

  var bs = window.getComputedStyle(element, null).backgroundSize;
  switch (bs) {
    case 'cover': console.log(Math.min(fx, fy)); break;
    case 'contain': console.log(Math.max(fx, fy)); break;
    case '100% 100%': console.log(fx, fy);
    default: console.log("Umm...");
  }
}

Default case is more complicated. Since each part of background size can be presented in number of units, code correctly handling those units will be a bit spaggettish and ugly.

jQuery based fiddle

mixture
  • 157
  • 2
  • 12
4

The background-size property specifies the size of the background image, not its "zoom factor". The only thing that you can get from this property is, well, its size. If such factor existed it would be in another property (-ies). You are digging in the wrong place.

Answering this question I had to ask myself another one. Does this number exist?

Let's imagine first that it does and the value is say 2.135 (twice as big as the original). What would happen to that number if I change the cover to 100% 100%. In this case the say "horizontal zoom factor" remained the same as cover's while the "vertical" zoom factor changed differently. What do you expect this number to be? How should it change?

The fact that one factor may change and the other may not leads me to assuming that they may (and should) be separate values (who knows, maybe "-vendor-background-size-x-zoom-factor" and "-vendor-background-size-y-zoom-factor" both of which may have positive and negative values and both of which are not included into any css-specs and both of which will remain under the hood of the browser, supposing they are in the form of css-properties, and not simply variables or who knows what).

In reality it may be a bit more complicated of course ))

skip405
  • 6,119
  • 2
  • 25
  • 28
  • what i was trying to say that even if you manage to decode the `cover` by javascript - you will get something like `150px 20px` which is not the zoom factor you seek. – skip405 Jan 23 '14 at 17:45
  • The existence of this zoom factor is questioned when I change the `cover` (which can be seen here: http://jsfiddle.net/skip405/AyBEN/) to `100% 100%` (http://jsfiddle.net/skip405/AyBEN/1/). Try to compare the two images and try to find the zoom factor on the *second*. If you reread my answer with two fiddles before your eyes - probably it will become clearer. – skip405 Jan 23 '14 at 17:48
  • I doubt that it is *zoomed*, @abernier, in my opinion the browser distorts the image using the same method no matter what properties I specify :). Instead of `cover` - have a look at its brother (`250px 250px`) - http://jsfiddle.net/skip405/AyBEN/2/. Instead of `100% 100%` have a look at `250px 150px` - http://jsfiddle.net/skip405/AyBEN/3/. Do you think that if the numbers in the property are equal it *zooms* and if they are not - it *distorts*?? I seriously doubt it. It's distortion all the time, IMO – skip405 Jan 23 '14 at 18:15
  • you are right. I've just rephrased the question in order to clarify. thank you – abernier Jan 29 '14 at 13:57
3

It's not yet an answer, but tests I'm having...

I had a little test with a similar property background-position which also accepts keywords like center, left...(which implies %), as background-size does for cover/contain

Let's sandboxing a div with

var div = document.createElement('div');
div.style.cssText = "background-position:center 3%;";
document.body.appendChild(div);

now let's retrieve that center value with:

window.getComputedStyle(div, null)
      .getPropertyCSSValue('background-position-x')
      .getFloatValue(CSSPrimitiveValue.CSS_PERCENTAGE);

and guess what ?

50

Unfortunately,

var div = document.createElement('div');
div.style.cssText = "background-size:cover;";
document.body.appendChild(div);
window.getComputedStyle(div, null)
      .getPropertyCSSValue('background-size')
      .getFloatValue(CSSPrimitiveValue.CSS_PERCENTAGE);

throws an Error:

InvalidAccessError: A parameter or an operation was not supported by the underlying object.

thomaux
  • 19,133
  • 10
  • 76
  • 103
abernier
  • 27,030
  • 20
  • 83
  • 114
  • 1
    Interesting. I tried a couple things but it looks like that we can only get 'cover' out of it, keywords are not translated to actual numbers. If you try setting something like `background-size: 10px 20px` you'll actually see a `CSSValueList` with two separate `CSSPrimitiveValue` of type `CSS_PX`. `cover` instead is of type `CSS_IDENT` — which I wish someone told me what it is. – fregante Jan 22 '14 at 02:20
  • http://www.w3.org/2003/01/dom2-javadoc/org/w3c/dom/css/CSSPrimitiveValue.html#CSS_IDENT – abernier Jan 22 '14 at 02:37
2

The short answer is browsers do not provide a way to get the computed value of the scale factor of background image, but you can compute it yourself according to the rules described in the spec.

Spadar Shut
  • 15,111
  • 5
  • 47
  • 54
0

You can check the size of the div and the original image, find out if the width or the height of the div is shorter proportionally that means the image is stretched to 100% of the smaller side. For example: If the container div is 600px X 500px and the size of the image is 600px X 400px the image will resize to cover the entire div so it will be resized to auto X 500px, meaning the zoom of the image will be 500/400 = 1.25

Lior Asta
  • 121
  • 3
  • 3
    The OP Specifically said they don't want to compute the scale factor themselves, but rather simply retrieve it via an API call. (If one exists.) – Dryden Long Jan 22 '14 at 00:24
  • If you are using this in javascript that's the only way I think it can be done. – Lior Asta Jan 22 '14 at 00:33
0

There is no way to do this as it would require the image to be loaded in order to give you an accurate value. Even if this value was exposed, you would have to wait for the window.load event before you could retrieve it... at which point it's faster to just calculate the value on your own.

UPDATE: From the CSS spec, background size behaves differently under different conditions - whether the image has intrinsic dimensions/ratio (jpeg/svg) or not (css gradient), whether both values are set to "auto" (in which case it's treated as "contain"), whether one of the "background-repeat" values is set to "round", whether there are multiple backgrounds... you get the point.

Also, background-size requires layout (changes with the layout) but is not in the list of properties which are calculated post-layout to an actual "used" value. This is important because getComputedStyle returns the actual "used" value, but "background-size" does not go through the process of computed value -> used value.

Couple this with the fact that you can't even get a value until the image is loaded... I still submit that computing it on your own sounds like your best bet.

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96
  • Not sure why the downvote. Nobody has even mentioned the fact that you have to wait for the image to load. It would be like trying to get the width of regular `` before the image has loaded. You have to wait - no way around it. – Ryan Wheale Jan 28 '14 at 20:34
-1

try:

background-size: contain

This will zoom in/out and fit the background size depending on device pixel ratio. No javascript or any computing required here as browser will perform rest of the tasks itself.