43

Is it possible to use JavaScript to get the actual size (width and height in pixels) of a CSS referenced background image?

7 Answers 7

63

Yes, and I'd do it like this...

window.onload = function () {
  var imageSrc = document
    .getElementById('hello')
    .style.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, '$2')
    .split(',')[0];

  // I just broke it up on newlines for readability

  var image = new Image();
  image.src = imageSrc;

  image.onload = function () {
    var width = image.width,
      height = image.height;
    alert('width =' + width + ', height = ' + height);
  };
};

Some notes...

  • We need to remove the url() part that JavaScript returns to get the proper image source. We need to split on , in case the element has multiple background images.
  • We make a new Image object and set its src to the new image.
  • We can then read the width & height.

jQuery would probably a lot less of a headache to get going.

Sign up to request clarification or add additional context in comments.

17 Comments

Code posted here and code on JSbin are different. Your regexp in replace has a bug. Here more correct version .replace(/url\(['"]?(.*)['"]?\)/gi, '$1')
this does not handle data urls because of the split. I removed the split as I only use a single background, but otherwise an additional if statement needs to be used to check the presence of data:
document.getElementById('hello').attributes.src.value works for me
@ZacharyRyanSmith I just tried it with a background image and it appeared the src property wasn't defined on attributes. Are you sure it's a background image, not a normal img element?
You should set the width and height in an image.onload handler; if you don't do this the width/height can be 0 if your internet connection is slow or the image is big.
|
14

Can't comment under answers, so here is jQuery version including background-size (posted because this question is first one in google search and may be useful to someone else than me):

function getBackgroundSize(selector, callback) {
  var img = new Image(),
      // here we will place image's width and height
      width, height,
      // here we get the size of the background and split it to array
      backgroundSize = $(selector).css('background-size').split(' ');

  // checking if width was set to pixel value
  if (/px/.test(backgroundSize[0])) width = parseInt(backgroundSize[0]);
  // checking if width was set to percent value
  if (/%/.test(backgroundSize[0])) width = $(selector).parent().width() * (parseInt(backgroundSize[0]) / 100);
  // checking if height was set to pixel value
  if (/px/.test(backgroundSize[1])) height = parseInt(backgroundSize[1]);
  // checking if height was set to percent value
  if (/%/.test(backgroundSize[1])) height = $(selector).parent().height() * (parseInt(backgroundSize[0]) / 100);

  img.onload = function () {
    // check if width was set earlier, if not then set it now
    if (typeof width == 'undefined') width = this.width;
    // do the same with height
    if (typeof height == 'undefined') height = this.height;
    // call the callback
    callback({ width: width, height: height });
  }
  // extract image source from css using one, simple regex
  // src should be set AFTER onload handler
  img.src = $(selector).css('background-image').replace(/url\(['"]*(.*?)['"]*\)/g, '$1');
}

or as jQuery plugin:

(function ($) {
// for better performance, define regexes once, before the code
var pxRegex = /px/, percentRegex = /%/, urlRegex = /url\(['"]*(.*?)['"]*\)/g;
$.fn.getBackgroundSize = function (callback) {
  var img = new Image(), width, height, backgroundSize = this.css('background-size').split(' ');

  if (pxRegex.test(backgroundSize[0])) width = parseInt(backgroundSize[0]);
  if (percentRegex.test(backgroundSize[0])) width = this.parent().width() * (parseInt(backgroundSize[0]) / 100);
  if (pxRegex.test(backgroundSize[1])) height = parseInt(backgroundSize[1]);
  if (percentRegex.test(backgroundSize[1])) height = this.parent().height() * (parseInt(backgroundSize[0]) / 100);
  // additional performance boost, if width and height was set just call the callback and return
  if ((typeof width != 'undefined') && (typeof height != 'undefined')) {
    callback({ width: width, height: height });
    return this;
  }
  img.onload = function () {
    if (typeof width == 'undefined') width = this.width;
    if (typeof height == 'undefined') height = this.height;
    callback({ width: width, height: height });
  }
  img.src = this.css('background-image').replace(urlRegex, '$1');
  return this;
}
})(jQuery);

11 Comments

Lovely! The jQuery plugin worked perfectly for me. Everyone, this function gives the scaled image size. Thanks very much!
Whoops! Sorry, it gives the unscaled image size. But I still like it!
There's a potential bug in that regexp. Here's the correct one: urlRegex = /url\(['"]*(.*?)['"]*\)/g
@neochief thanks, fixed that, totally forgot someone can use " in the url()
Сouldn't you explain how to use it? Or give an example. Both the function and the plugin. Thanks.
|
10
var actualImage = new Image();
actualImage.src = $('YOUR SELECTOR HERE').css('background-image').replace(/"/g,"").replace(/url\(|\)$/ig, "");

actualImage.onload = function() {
    width = this.width;
    height = this.height;
}

1 Comment

What if the background image is scaled and you want to get the scaled width and height values?
6
var dimension, image;

image = new Image();
image.src = {url/data}
image.onload = function() {
    dimension = {
        width: image.naturalWidth,
        height: image.naturalHeight
    };
    console.log(dimension); // Actual image dimension
};

2 Comments

Despite how old this question and this answer is, this is what worked for me. I also edited the answer to fix a syntax issue and used Killah's helpful regex expression in setting the image.src variable.
using 'naturalWidth' and 'naturalHeight' works like a charm
2

Here it is in jQuery:

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

actualImage.width // The actual image width
actualImage.height // The actual image height

Thanks for the sweet regex alex.

1 Comment

Except that this doesn't work in Chrome. FF seems to load the image but Chrome doesn't. So the width and height properties of actualImage are always 0.
0

If you're using React you can create a custom hook:

import { useEffect, useState, useCallback, useRef } from 'react'

const urlRgx = /url\((['"])?(.+?)\1\)/
const getImagePromise = src =>
  new Promise(resolve => {
    const img = new Image()

    img.onload = () =>
      resolve({
        src,
        width: img.naturalWidth,
        height: img.naturalHeight
      })
    img.src = src
  })
const useBackgroundImageSize = (asCallbackFlagOrUrls = false) => {
  const ref = useRef()
  const [images, setImages] = useState(null)
  const callback = useCallback(async () => {
    if (Array.isArray(asCallbackFlagOrUrls)) {
      const imgPromises = asCallbackFlagOrUrls.map(getImagePromise)
      const imgs = await Promise.all(imgPromises)

      if (ref?.current) {
        setImages(imgs)
      }
    }

    if (typeof asCallbackFlagOrUrls === 'string') {
      const image = await getImagePromise(asCallbackFlagOrUrls)

      if (ref?.current) {
        setImages(image)
      }
    }

    if (typeof asCallbackFlagOrUrls === 'boolean') {
      if (ref.current) {
        const matches = window
          .getComputedStyle(ref.current)
          .backgroundImage.match(new RegExp(urlRgx, 'g'))

        if (Array.isArray(matches)) {
          const imgPromises = matches.map(match =>
            getImagePromise(match.replace(new RegExp(urlRgx), '$2'))
          )
          const imgs = await Promise.all(imgPromises)

          if (ref?.current) {
            setImages(imgs.length > 1 ? imgs : imgs[0])
          }
        }
      }
    }
  }, [ref, asCallbackFlagOrUrls])

  useEffect(() => {
    if (asCallbackFlagOrUrls !== true) {
      callback()
    }
  }, [asCallbackFlagOrUrls, callback])

  return asCallbackFlagOrUrls === true ? [ref, images, callback] : [ref, images]
}

export { useBackgroundImageSize }

Then use it like:

const App = () => {
  const [ref, image] = useBackgroundImageSize()

  console.log(image) // { width, height, src }

  return <div ref={ref} image={image} />
}

You can also install background-image-size-hook and use it as a dependency. See the README for more usage details.

Comments

0

Here is a fixed version of the code from klh's post. I pointed out some small mistakes on the comment section of his post and was told please edit it. And so I did. However, reviewers Jan Wilamowski and Dave rejected it.

"This edit was intended to address the author of the post and makes no sense as an edit. It should have been written as a comment or an answer."

Apparently they did not see the comments section.

I had no choice but to write the revised code as a new answer.

function getBackgroundSize(selector, callback) {
  var img = new Image(),
      // here we will place image's width and height
      width, height,
      // here we get the size of the background and split it to array
      backgroundSize = $(selector).css('background-size').split(' ');

  // checking if width was set to pixel value
  if (/px/.test(backgroundSize[0])) width = parseInt(backgroundSize[0]);
  // checking if width was set to percent value
  if (/%/.test(backgroundSize[0])) width = $(selector).width() * (parseInt(backgroundSize[0]) / 100);
  // checking if height was set to pixel value
  if (/px/.test(backgroundSize[1])) height = parseInt(backgroundSize[1]);
  // checking if height was set to percent value
  if (/%/.test(backgroundSize[1])) height = $(selector).height() * (parseInt(backgroundSize[1]) / 100);

  img.onload = function () {
    // check if width was set earlier, if not then set it now
    if (typeof width == 'undefined') width = this.width;
    // do the same with height
    if (typeof height == 'undefined') height = this.height;
    // call the callback
    callback({ width: width, height: height });
  }
  // extract image source from css using one, simple regex
  // src should be set AFTER onload handler
  img.src = $(selector).css('background-image').replace(/url\(['"]*(.*?)['"]*\)/g, '$1');
}

JQuery

(function ($) {
// for better performance, define regexes once, before the code
var pxRegex = /px/, percentRegex = /%/, urlRegex = /url\(['"]*(.*?)['"]*\)/g;
$.fn.getBackgroundSize = function (callback) {
  var img = new Image(), width, height, backgroundSize = this.css('background-size').split(' ');

  if (pxRegex.test(backgroundSize[0])) width = parseInt(backgroundSize[0]);
  if (percentRegex.test(backgroundSize[0])) width = this.width() * (parseInt(backgroundSize[0]) / 100);
  if (pxRegex.test(backgroundSize[1])) height = parseInt(backgroundSize[1]);
  if (percentRegex.test(backgroundSize[1])) height = this.height() * (parseInt(backgroundSize[1]) / 100);
  // additional performance boost, if width and height was set just call the callback and return
  if ((typeof width != 'undefined') && (typeof height != 'undefined')) {
    callback({ width: width, height: height });
    return this;
  }
  img.onload = function () {
    if (typeof width == 'undefined') width = this.width;
    if (typeof height == 'undefined') height = this.height;
    callback({ width: width, height: height });
  }
  img.src = this.css('background-image').replace(urlRegex, '$1');
  return this;
}
})(jQuery);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.