4

Curious problem. I have a set of images with some attributes that I'd like to use in a div (as a caption). Using each, I want to get the width of the image (and some other properties), to align the dynamically generated div properly (as a caption of the image).

img = $('img') 
img.each(function(index){
    var width = $(this).width();
    console.log(width);
    // other properties
    $('<div class="caption">Some text</div>').insertAfter($(this));

$(this).next().css({
  'width': width
  // other properties
});

However, sometimes $(this).width() gets the right value, other times gets 0. It's particularly well behaved when a press return in the direction bar but not when I press Ctrl+R but only in Chrome. It doesn't work the same in all browsers, so it's a mess. I thought that Jquery was attempting to retrieve width() before the image was loaded, so I wrap my code in document.ready(function(){}) instead of (function(){})() but it doesn't work either way.

What could be happening?. Just as a reference, these are the styles applied to the images:

display: block;
padding: 4px;
line-height: 1;
max-width: 100%;
margin-left: auto;
margin-right: auto;

So I'd like to get the computed width (which, as far as I know, should be retrieved by .css(), but in this case, not consistently).

Regards

r_31415
  • 8,752
  • 17
  • 74
  • 121

2 Answers2

3

jQuery won't wait for images in $(document).ready().
Try $(window).load() instead as mentioned in example 5 here

Andreas
  • 21,535
  • 7
  • 47
  • 56
  • `$(window).ready` is exactly the same as `$(document).ready`, read here: http://stackoverflow.com/questions/10753306/why-readyhandler-is-not-recommended/10756299#10756299 Maybe you meant `$(window).load`? – Kevin B Jun 04 '12 at 19:17
  • Interesting. .load() fixed it in Chrome but not in Firefox. It set width() correctly but the other properties I was talking about (margin-left, margin-right) are set to 0 while in Chrome they have correct values. – r_31415 Jun 04 '12 at 19:24
  • No, sorry... a bit unreliable also in Chrome with last images. – r_31415 Jun 04 '12 at 19:27
2

More than likely the images aren't completely loaded all the time when you run that code. Try ensuring that the images are done loading first.

function imgDone(){
    var width = $(this).width();
    console.log(width);
    // other properties
    $('<div class="caption">Some text</div>').insertAfter($(this));
}
$('img').each(function(index){
    if (this.complete || this.readyState = 4)
        imgDone.apply(this);
    else
        $(this).load(function(){
            imgDone.apply(this);
        });
});
Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • Good, I will try that. This seems to be the issue since as per Andreas suggestion, .load fixed it in Chrome but not in Firefox with other properties. – r_31415 Jun 04 '12 at 19:25
  • Great, now is working in Chrome all the times (I think), but for some reason, it's extending the width a huge amount in Firefox even after I removed everything related to width (probably I made a mistake since this doesn't make sense. – r_31415 Jun 04 '12 at 19:45
  • No, you were correct. As I thought, I made a silly mistake where I didn't set width: 100% so the image overflowed quite a bit. Yet I don't understand the second part of your code... you say, check every image to see if it has loaded completely. If it has, do the Jquery part or whatever but if it hasn't... what?. $(this).load is not equivalent to this.complete || this.readyState or what is the difference?. – r_31415 Jun 04 '12 at 20:06
  • .load when used on an image will fire when the image finishes loading. the complete and readystate conditional checks whether or not the image is already loaded, in which case the load event may not trigger in some circumstances ( dependant on the order of adding load event vs setting src value ). You may be able to get rid of the if statement and simply use .load(onDone), make sure you test it in IE8 – Kevin B Jun 04 '12 at 20:10
  • Should that really be an assignment in the `if`'s condition? – alex Jun 22 '12 at 03:58