3

I have a need to resolve (i.e. 'apply', not just load into memory) all styles for all elements of a HTML webpage with some javascript/jquery. The styles may be in-line within the element's style tag, in-line within the page's styles, or external from a stylesheet.

I have seen examples resolving a single element, or even a single style using window.getComputedStyle with a setTimeout, but I need to make sure all elements are resolved (not just one or even a group).

(Note that I have a lot of javascript running after the page is loaded which generates further html (with styles) so document.ready and window.load have already fired by the time the page's javascript completes)

(Note also that this is not simply a question about waiting for a stylesheet file to load - it is more about waiting for the styles from all sources to be applied)

Is this possible ?

UPDATE

Based on example from @Kaiido, I have come up with the following (it uses JQuery Deferred as opposed to Javascript Promise - this is because I am more familiar with Deferred and I need it to conform with inhouse JQuery standards)

<style>
    .myStyle {...}
    .myStyle2 {...}
</style>

var cssIsAppliedPromise = function(){
    var trigger = document.createElement('style');
    trigger.innerHTML = 'body{opacity:1;}';
    var waiter = document.createElement('style');
    waiter.innerHTML = 'body{transition : opacity 0.1s linear; opacity:.9}';
    var deferred = $.Deferred();
    // will trigger only when all styles are applied
    function isDone(evt) {
        // some cleanup
        waiter.parentNode && document.head.removeChild(waiter);
        trigger.parentNode && document.head.removeChild(trigger);
        // resolve the promise
        deferred.resolve();
    }
    document.body.addEventListener('transitionend', isDone, {
        once: true
    });
    document.head.appendChild(waiter);
    // append it only when all resources are fetched
    window.onload(function() {
        document.body.offsetWidth; // trigger a reflow
        document.head.appendChild(trigger);
    });
    return deferred.promise();
}
cssIsAppliedPromise.done(function(){
        //logic after styles applied
});

Although this seems to work I'm not sure whether it does - it is difficult to tell - the problem I have still exists. How can I be sure the above actually applies the styles before continuing to "logic after styles applied"?

TerrorBight
  • 334
  • 4
  • 23
  • 1
    Possible duplicate of [jQuery Append CSS File and Wait until styles are applied without setInterval?](https://stackoverflow.com/questions/32085700/jquery-append-css-file-and-wait-until-styles-are-applied-without-setinterval) – Kaiido Sep 07 '17 at 14:19
  • Thanks Kaiido - the link provided is more about waiting for a stylesheet file(s) to load - I'm asking more about waiting for the styles (from all sources - element style tag, in-line styles, external styles) to be applied to all html elements – TerrorBight Sep 07 '17 at 14:26
  • 1
    transitionend event will do that. See provided link – Alex Slipknot Sep 07 '17 at 14:27
  • 1
    From linked question : "*It works, but I have a function that needs to run **after the CSS has been applied***" – Kaiido Sep 07 '17 at 14:28
  • Thanks @Kaiido / AlexSlipknot - I'm not exactly clear on what you're suggesting - I have a webpage with an inline style with many classes - i.e. within ... and many HTML elements that refer to these classes as well as having their own styles (as in ...
    ...). How do wait (I assume via a transitionend event) until all of these styles have been applied
    – TerrorBight Sep 07 '17 at 14:45
  • 1
    In your case you don't even need the stylesheets to be in external files, you can simply append them directly in the head. Here is a rewrite of the previous answer as a js function: https://jsfiddle.net/5dup24nz/ – Kaiido Sep 07 '17 at 14:57
  • *"Note that I have a lot of javascript running after the page is loaded which generates further html"* Do you have script that may run depending on user interaction? Does this script run later because it's scheduled to do so? What exactly does this script do? What is the purpose of your mystery code? Do you have any code? – zer00ne Sep 07 '17 at 15:30
  • I've added an "Update" to the original post - the "lot of Javascript" is actually DustJS code (i.e. generated out of template) - this means that the life-cycle of the page is not really typical in that the page is downloaded, the Dust code then runs (which generates a lot more html with styles to be applied). There is also an additional complexity in that what is ultimately trying to be achieved is that the code is pushed into ExpertPDF (a PDF generator) - all works well except for this last edge case where the PDF is generated before it has time to apply its styles to the individual elements – TerrorBight Sep 08 '17 at 15:23
  • That's still very unclear. Is the loading of this *Dust code*'s content (by the way what is *Dust code*?) genrerated **a**synchrounously? What is this *ExpertPDF* thing you are talking about? The [.net library](www.expertpdf.net)? My method will work only for elements that are being appended at least prior to the end of onload event, not for the ones that are being appended asynchronously after this event. And all in all, th only way for us to tell you would be that you do provide us an [MCVE]. – Kaiido Sep 09 '17 at 04:18

0 Answers0