Ben
Ben

Reputation: 11502

How to get a computed CSS style before window.load?

I've got a custom slideshow page with hundreds of large pictures in markup. In addition, there is an adjustment to the layout that can't be done with CSS alone, and requires javascript. That adjustment depends on the computed CSS styles of a couple page elements.

Here's the issue: getting a computed CSS style on (document).ready doesn't seem to work. That makes perfect sense, because layout/paint haven't occurred yet when the DOM is merely registered.

(window).load is the obvious answer here. But the waiting period for (window).load is maddeningly long in this case, because it takes literally 30 seconds (longer on slow connections!) for all the 100+ large images to be downloaded. That's fine in principle for the slideshow, because the slideshow starts being usable once the first two images are loaded, long before all the images are loaded. The thing is, I'd like the scripted CSS layout correction to occur at that point as well.

To check for imgs being loaded, I'm use imageLoaded, which is great, and gets around the issues with jquery's load event when used with imgs. But how do I check for "load"-like events (and the availability of computed styles) on a page element, for example a div? (I realize divs don't fire load events.) In principle, is there a reliable cross-browser DOM event in between (document).ready and (window).load that I can listen for on a particular set of elements, to get computed styles? Or am I forced to choose between these two temporal extremes?

Upvotes: 2

Views: 3702

Answers (3)

Yatharth Agarwal
Yatharth Agarwal

Reputation: 4564

On CSS load

Source: https://stackoverflow.com/a/12570580/1292652

Add a unique reference styles to the CSS files you want to check for like so:

#ensure-cssload-0 {
  display: none;
}

Then, use a JS function, cssLoad(), to repeatedly check whether the CSS has been downloaded (not sure if this is significantly different from when the CSS is actually painted/rendered):

var onCssLoad = function (options, callback) {
    var body = $("body");
    var div = document.createElement(constants.TAG_DIV);
    for (var key in options) {
        if (options.hasOwnProperty(key)) {
            if (key.toLowerCase() === "css") {
                continue;
            }
            div[key] = options[key];
        }
    }

    var css = options.css;
    if (css) {
        body.appendChild(div);
        var handle = -1;
        handle = window.setInterval(function () {
            var match = true;
            for (var key in css) {
                if (css.hasOwnProperty(key)) {
                    match = match && utils.getStyle(div, key) === css[key];
                }
            }

            if (match === true) {
                window.clearTimeout(handle);
                body.removeChild(div);
                callback();
            }
        }, 100);
    }
}

You can use it as:

onCssLoad({
    "id": <insert element CSS applies to>,
     css: <insert sample CSS styles>
}, function () {
    console.log("CSS loaded, you can show the slideshow now :)");
});


On CSS computation

Source: http://atomicrobotdesign.com/blog/javascript/get-the-style-property-of-an-element-using-javascript/

The previous solution only told if a CSS file had been 'downloaded', while in your question you mention you need to know when a style for an element has been 'computed' or 'rendered' or 'painted'. I hope this might resolve that.

Add a unique reference styles to the CSS files you want to check for like so:

#ensure-cssload-0 {
  ignored-property: 'computed';
}

Now, use getPropertyValue and getComputedStyle to check for the CSS:

function getStyle(elem, prop) {
    return window.getComputedStyle(elem, null).getPropertyValue(prop);
}

Now, just use a while loop with a callback:

function checkStyle(elem, prop, callback) {
    while ( getStyle(elem, prop) !== 'computed' ) {
        // see explanation below
    }
    callback()
}

Since JavaScript doesn't have a pass statement (like in Python), we use an empty code block.

If you want to retrieve all the CSS styles applied to an element (warning: this will also show inherited styles), check out this SO answer.


Avoiding the while() loop

Using while loops to check for anything is usually NOT recommended as it hangs uo the browser doesn't let the JavaScript thread do anyting else (all browsers nowadays are multithreaded, see this comic).

Here's Chuck suggested, this solution is much better:

function checkStyle(elem, prop, callback) {
    if ( getStyle(elem, prop) !== 'computed' ) {
        // see explanation below
        window.setTimeout( function() {checkStyle(elem, prop, callback);}, 100 )
    } else {
        callback()
    }
}

This is much better. Now the function asynchronously checks every 100ms (you can change this value if you want). The wrapping of the function while setting the timeout was necessary as setTimeout() doesn't allow passing of any arguments yet.

Hope this helped. See the source code of this post for some more links...

Upvotes: 3

Yatharth Agarwal
Yatharth Agarwal

Reputation: 4564

My other answer only told you when a CSS file had been downloaded, while in your question you mention you need to know when a style for an element has been computed or rendered or painted- has been updated.

I hope this addresses the issue (I didn't want to merge this with the other answer as I felt it attacked a different angle...) I changed my mind, see the edit.

Source: http://atomicrobotdesign.com/blog/javascript/get-the-style-property-of-an-element-using-javascript/

Add a unique reference styles to the CSS files you want to check for like so:

#ensure-cssload-0 {
  ignored-property: 'computed';
}

Now, use getPropertyValue and getComputedStyle to check for the CSS:

function getStyle(elem, prop) {
    return window.getComputedStyle(elem, null).getPropertyValue(prop);
}

Now, just use a while loop with a callback:

function checkStyle(elem, prop, callback) {
    while ( getStyle(elem, prop) !== 'computed' ) {
        // see explanation below
    }
    callback()
}

Since JavaScript doesn't have a pass statement (like in Python), we use an empty code block.

If you want to retrieve all the CSS styles applied to an element (warning: this will also show inherited styles), check out this SO answer

Upvotes: 0

Maxim Antonov
Maxim Antonov

Reputation: 305

You can use DOMContentLoaded event. It fires when dom tree is ready and styles applyed. window.load fires, when all images and scripts loaded.

if you using jQuery, you can use this:

$(function(){
 // this fn not waiting for images
  $('.selector-class')[0].style ;// this is your computed style OR...
  $('.selector-class').css(); // json representation of style;
});

if you have no jQuery on page ... in modern browsers you can use this code:

document.addEventListener( "DOMContentLoaded", function(){
  var computedStyle = document.querySelector('#yourElementId').style ; 
})

YatharthROCK Addedd very precission solution below.

Upvotes: 1

Related Questions