Oli
Oli

Reputation: 239830

Earliest event to get an image's width

I've got some JavaScript to center images and <object>s on a page if they're over a threshold width. It also checks that certain classes haven't already been manually applied.

$('img,object').bind('load', function() {
    w = $(this).width();

    if (w > 400 && !( $(this).hasClass('inlineimage') | $(this).parent().hasClass('inlineimage') ))
        $(this).css('margin', '10px ' + (parseInt((800-w)/2)-30) +'px');
});

It's horrific but the meaning behind this was all originally quite sane. The CMS doesn't make it easy to specify alignment and developing it to allow this would have taken significant time away from other jobs. A client-side hack works.

The only problem with it is that the JS waits until the whole image has loaded. Obviously this means that on slower networks, the page loads, the images start loading and some time later the images snap into position. Ugly.

But the browser seems to know the width of an image as soon as it starts to download it. I would really love to hook into this event and splat this visual bug.

Of course, if there's a CSS way of approaching this, I'm open to that too.

Upvotes: 4

Views: 179

Answers (3)

Some Guy
Some Guy

Reputation: 16210

var span = document.getElementById('span'); // The parent span

var check = function (){
    if(span.offsetWidth > 0){
        console.log('Width while loading', span.offsetWidth);
    }
    else{
       setTimeout(check, 100);
    }
};
check();

Demo. This should show the width in the console while it's loading first, and then the width after it's loaded. That is as long as the image isn't cached. (If the demo doesn't work for someone, try changing the hoo part of the image URL to anything else)

Upvotes: 1

Oli
Oli

Reputation: 239830

In the interest of this still working on more than the latest browsers, I've cobbled together a best effort brute force. It waits 500ms between attempts and checks images to see if the current run through is the same width as the last time it tried.

As soon as the width for an image is the same in two consecutive passes, we run the centring code.

This uses arrays to keep track of things so we're not constantly raping the DOM nor are we querying items that aren't applicable (because they've already been dealt with or ruled out).


attempts = 0;
arr = [];
$.each($('img,object').not('inlineimage'), function(){
    arr.push([this, -2, $(this).width()]);
});

checkImgs = function() {
    attempts++;
    newarr = []
    $.each(arr, function(){
        if ($(this[0]).parent().hasClass('inlineimage'))
            return;
        w = $(this[0]).width();
        this[1] = this[2];
        this[2] = w;
        if (this[1] != this[2])
            return newarr.push(this);

        // We know this image is loaded enough now - we can do things!
        if (w >= 400)
            $(this[0]).css('margin', '10px ' + (parseInt((800-w)/2)-30) +'px');
    });

    arr = newarr;
    if (arr.length && attempts < 6)
        setTimeout(checkImgs, 500);
}
setTimeout(checkImgs, 500);

It's not beautiful but it seems to work both efficiently (CPU was getting hammered by some of my earlier attempts) and quickly (cached images spring into place within 500ms).

Upvotes: 0

Esailija
Esailija

Reputation: 140230

In browsers that support it, you can poll for natural dimensions:

var interval = setInterval( function() {
    if( img.naturalWidth ) {
        clearInterval(interval);
        console.log( "Natural available: "+ (new Date - now );
        console.log( img.naturalWidth, img.naturalHeight );
    }
}, 0 );

In the demo here on uncached image I get:

Natural available: 782
62 71 
Loaded: 827 

So the real dimensions were available 50 milliseconds before load event. Unfortunately in IE, the readystate "loading" doesn't guarantee real dimensions.

Change the query string for the image before each test to ensure uncached.

Here's whatwg link on natural dimensions: http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#dom-img-naturalwidth

Upvotes: 2

Related Questions