img.on("load") executes after the img is loaded but before it has its size set (IE)

EDIT : Added jsfiddle

I've some images, that I want to load by assigning their "data-src" attribute value to theirs "src" attribute and vertically center them after.

It works without a problem in all browsers except IE (tested from 8 to edge).

In IE some images get centered without a problem, but some wont and it is because code in the .on("load") event gets executed (probably) after the image is loaded, but before it gets its size set.

Is there any way to always execute the code after the image is loaded and its size is set (in IE)?

for (i = 0; i < 100; i++)
{
    targetSrc = $divElement.eq(i).children(imgClass).attr(dataSrc) + "?v=" + datetime;  

    $divElement.eq(i).find(imgClass).attr("src", targetSrc).on("load", function()
    {
        $holder.append($(this).attr("src") + " || height = " + $(this).height() + "<br>");
    });
}

Upvotes: 1

Views: 193

Answers (1)

Shikkediel
Shikkediel

Reputation: 5205

Initially thought requestAnimationFrame and a timeout fallback could easily solve this but it turned out to be a lot more complicated. Apparently the exact frame at which an image is rendered after onload is not very predictable in IE. But I eventually came up with this solution that checks the naturalHeight against the current height to see if an image has been rendered, looping through to the next display frame when it is not the case yet :

https://jsfiddle.net/r8m81ajk/

$(function() {

    if (window.requestAnimationFrame) var modern = true;

    var element = $('.divElement'),
    reference = '.imgElement',
    holder = $('.holder'),
    datetime = Date.now(),
    path, image;

    for (var i = 0; i < 100; i++) {

    var target = element.eq(i).children(reference),
    path = target.data('src') + '?v=' + datetime;

    target.one('load', function() {

        image = this;

        if (modern) requestAnimationFrame(function() {
        nextFrame(image);
        });
        else setTimeout(renderImage, 50);

    }).attr('src', path);
    }

    function nextFrame(picture) {

        var dimension = $(picture).height();

        if (dimension == picture.naturalHeight) {
        holder.append('height = ' + dimension + '<br>');
        }
        else nextFrame(picture);
    }

    function renderImage() {

        holder.append('height = ' + $(image).height() + '<br>');
    }
});

The fallback will always check on the third frame (when there's no bottleneck). Don't mind I adapted the code a bit to my usual conventions, the external references should have remained the same.

From the question I realise the loop might not even be needed and getting naturalHeight when the image loads would be enough. Interesting exercise to detect the exact point of rendering in any case.

Upvotes: 1

Related Questions