views:

1111

answers:

4

I ran into a problem on Chrome and Safari using jQuery to do some calculations using the widths of a strip of images.

When using my calculations in:

$(document).ready(function() {
    /* some calculations with $("img").width() */
});

everything works just fine in IE6+ and Firefox, but it does not in Chrome and Safari: $(img).width() is 0 whether the image is already cached or not.

Using:

$(window).load(function() { 
    /* some calculations with $("img").width() */
});

it works in all the above mentioned browsers but the problem is it only starts when all images are completely loaded.

Is the webkit behaviour the expected behaviour or is there some webkit / jQuery bug causing the image properties not to be a part of the DOM?

If it is a problem with webkit / jQuery: Is there a way around it that will allow my script to execute earlier than in the above mentioned solution?

By the way, I am not using any inline properties for the image dimensions.

+2  A: 

Try specifying the sizes in your img tags:

<img src="myimg.jpg" alt="" width="300" height="200" />

A quick google search about this: http://www.websiteoptimization.com/speed/tweak/size/

What I'm deducing is since the images aren't loaded, webkit will simply return 0 as an 'unknown' size until the image has been loaded. Specifically stating the size might solve this.

Jeff
Thanks, that indeed works as well, but it does not really allow for dynamically added pictures from a database; I don´t want to calculate each with in php before displaying the picture if I can avoid it (to avoid overhead)...
jeroen
You could precalculate the image sizes and store it in the database (if you can/want).I don't have a webkit browser on hand (I'm at work), so I can't try building a test-case to debug.
Jeff
I was hoping to solve it all on the client side, if possible.
jeroen
+1  A: 

I feel this is more of hack-ish way, but it seems to work (from what I've tested):

function callback(){
    var el = $(this);
    // if this element was processed or width is 0 (for webkit), then skip
    if(el.data('loaded') || el.width() === 0)
        return;
    el.data('loaded', 1); // marked this element as "processed"
    // do whatever you want to do with el.width()
    console.log(el.width());
}
$(function(){
    // Non-webkit-based browsers will call callback() here
    // otherwise, after each image loads, the callback will execute
    // (for webkit browsers), when the size will be correct.
    $('img').load(callback).each(callback);
})

Webkit-browsers will still be slightly slower than other browsers because it's after each image finishes loading, but it's faster than waiting for all the images to load.

Jeff
Nice, thanks! I´m not sure if I´ll use it though, it doesn´t feel quite right...
jeroen
+1  A: 

I'm not a fan of offloading tasks to the client that should be handled on the server.

The real solution is to calculate the image-size when it is added to your database, then generating the <img> tag correctly with width and height attributes before sending it to the client.

Any overhead incurred in the initial calculation (and pulling the values from the database afterwards) would be minuscule compared to the process of uploading it to the database in the first place -- not to mention each subsequent retrieval of it later.

The result is a semantically meaningful HTML-tag that works with jQuery in all browsers you care about, so why avoid it?

brownstone
Good point. I'm still a bit surprised however that IE6+ and Firefox have the image properties available when the DOM is loaded and webkit hasn´t. As the information sent to the browser is the same, I'd think webkit has got it somewhere as well.
jeroen
+1  A: 

I found this way of specifying image sizes when dynamically loading images using .load(), I use an image loading function with a callback

loadImage: function(src, callback){
  $("<img alt="" />").attr("src", src).load(callback);
}

and then I can use the img-element (which reports the correct size) to set the img-attributes inside the callback

$(this).attr({
  id: img,
  width: this.width,
  height: this.height
});

and now I can get the proper widht and height using, for example,

var contentWidth = $("#img").attr("width");
Anders Zakrisson
Thanks for your answer. However, I think the callback is executed when the images are completely loaded, so that basically would give the same result as using the `$(window).load(function()` function.
jeroen
Yes, except that I can't use $(window).load() in my case since I load images on user actions, not in an orchestrated series of scripts.
Anders Zakrisson