views:

26679

answers:

12

I am creating a jQuery plugin.

How do I get real image width and height with Javascript in Safari?

Following works with Firefox 3, IE7 and Opera 9:

var pic = $("img")

// need to remove these in of case img-element has set width and height
pic.removeAttr("width"); 
pic.removeAttr("height");

var pic_real_width = pic.width();
var pic_real_height = pic.height();

But in Webkit browsers like Safari and Google Chrome values are 0...

Doing this on server side is not an option.

+2  A: 

this works for me (safari 3.2), by firing from within the window.onload event:

$(window).load(function() {
  var pic = $('img');

  pic.removeAttr("width"); 
  pic.removeAttr("height");

  alert( pic.width() );
  alert( pic.height() );
});
Owen
Yeah! Didn't work from $(document).ready(function(){});Thanks! It needs to have the image fully loaded before it can read it. Ofcourse.
Frank Bannister
+8  A: 

The root problem is that WebKit browsers (Safari and Chrome) load JavaScript and CSS information in parallel. Thus, JavaScript may execute before the styling effects of CSS have been computed, returning the wrong answer. In jQuery, I've found that the solution is to wait until document.readyState == 'complete', .e.g.,

jQuery(document).ready(function(){
  if (jQuery.browser.safari && document.readyState != "complete"){
    //console.info('ready...');
    setTimeout( arguments.callee, 100 );
    return;
  } 
  ... (rest of function)

As far as width and height goes... depending on what you are doing you may want offsetWidth and offsetHeight, which include things like borders and padding.

Cugel
Yeah, that's the reason. A better workaround is to use jQuery's load-event.
Frank Bannister
`$(window).load(function(){ ... });` helped in my case
o_O Tync
+1  A: 

Wow yes! IT's much better to use $window.load() than $document.ready().. I guess the DOM can be ready to be parsed much earlier than the images are done loading!

+18  A: 

Webkit browsers set the height and width property after the image is loaded. Instead of using timeouts, I'd recommend using an image's onload event. Here's a quick example:

var pic_real_width;
var pic_real_height;

$(img).load(function() {
    // Remove attributes in case img-element has set width and height
    $(this).removeAttr("width")
           .removeAttr("height")
           .css({ width: "", height: "" }); // Remove css dimensions as well

    pic_real_width = this.width;
    pic_real_height = this.height;
});

var src = img.src;
img.src = "";
img.src = src; // Triggers onload if image is cached (see comments)
Xavi
I'm testing on Firefox 3 and $(document).ready() also doesn't work as well.
hlfcoding
That's clever, didn't know you could do $(img).load();
SeanJA
On some browsers, load does not fire on a cached image (which makes me sad). Opera, for one. But Opera returns to correct width and height immediately, so you can work around that. Unfortunately, the latest Chrome on my machine seems to suffer from the same problem, so I'd say this solution is unreliable.
Nosredna
You're entirely correct Nosredna. I completely overlooked that case. In the past I've gotten around this bug/feature by executing `img.src = img.src` after I attached the img's onload event. I'll update my answer to handle this case.
Xavi
I recently learned that the `img.src = img.src` doesn't works in Chrome 3.0. That said, I believe I may have found a work around: set the image source to empty string then back to the original source. I'll update my answer.
Xavi
In addition to `width` and `height` you should probably also remove `min-width`, `min-height`, `max-width` and `max-height` as they could also influence the image dimensions.
mqchen
A: 

Thanx a lot Alex, this is simple and works very well ! I guess in complex pages with a lot of images and javascript, this might cause performance loss (useless delay before executing anything) and need the tips above at the right place, where these attrs are needed.

A: 

For functions where you do not want to alter the original placement or image.

$(this).clone().removeAttr("width").attr("width");
$(this).clone().removeAttr("height").attr("height);
Davin
+1  A: 

As Luke Smith says, image load is a mess. It's not reliable on all browsers. This fact has given me great pain. A cached image will not fire the event at all in some browsers, so those who said "image load is better than setTimeout" are wrong.

Luke Smith's solution is here.

And there is an interesting discussion about how this mess might be handled in jQuery 1.4.

I have found that it's pretty reliable to set the width to 0, then wait for the "complete" property to go true and the width property to come in greater than zero. You should watch for errors, too.

Nosredna
A: 

Amazing, Thanks so much. What a complete mess this all is, stupid we need all these workarounds all the time. Wasted about 6 hours trying to solve this problem, thankfully I came across this.

Ruben Meibergen
+2  A: 
FDisk
Since a few months, cloning an image with jquery (using the latest Chrome) and getting it's properties, always returns 0x0So far this is the only solutions that works (have tested all the others in this page)Before returning, I set t=null too.
UVL
A: 
$("#myImg").one("load",function(){
  //do something, like getting image width/height
}).each(function(){
  if(this.complete) $(this).trigger("load");
});

From Chris' comment: http://api.jquery.com/load-event/

Jerome Jaglale
+1  A: 

There is now a jQuery plugin, event.special.load, to deal with cases where the load event on a cached image doesn't fire: http://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js

Sergio1132
A: 

I looove Chrome but I cursed it to hell for being the browser that wouldn't read the dimensions of my freshly ajaxed images. After hours of searching and cursing this is the fix I came up with:

Do a fadeIn before reading any dimensions:

$('#image').fadeIn(10,function () { var tmpW = $(this).width(); var tmpH = $(this).height(); });

Dio