jQuery event that triggers after CSS is loaded?

jQuery event that triggers after CSS is loaded?

I have a couple of links on my page (inside a

) which allow you to change the CSS stylesheets:
$(‘#theme-selector a’).click(function(){
var path = $(this).attr(‘href’);
$(‘head link’).remove();
$(‘head’).append(‘‘);
return false;
});

Now, after I’ve changed the style on the page, I want to get the new background color, using the following code (which I put after the $(‘head’).append call):
var bgcolor = $(‘body’).css(‘background-color’);
alert(bgcolor);

The problem is, I think, that it takes some time for the browser to download the new stylesheet and I sometimes get the old background color in my alert message. Is there some event I can bind that will only alert me after all the stylesheets are loaded on the page?
At the moment, all I can think of is using a setTimeout(function(){}, 5000); which isn’t great, because what if it takes longer/shorter to load all the CSS on the page.
Let me know if I need to clarify anything and I can provide more code.

Solutions/Answers:

Solution 1:

Rather than creating a new link element and appending it to the head, you could retrieve the contents of the stylesheet with an AJAX call, and insert it into an inline style block. That way, you can use jQuery’s ‘complete’ callback to fire off your check.

$('#theme-selector a').click(function(){
  var path = $(this).attr('href');
  $.get(path, function(response){
   //Check if the user theme element is in place - if not, create it.
   if (!$('#userTheme').length) $('head').append('<style id="userTheme"></style>');

   //populate the theme element with the new style (replace the old one if necessary)
   $('#userTheme').text(response);

  //Check whatever you want about the new style:
  alert($('body').css('background-color'));
  });
});

I haven’t actually tested this code, so there may be some syntax-y errors, but the logic should be sound enough.

Related:  How are JavaScript arrays represented in physical memory?

Solution 2:

The load event can be watched for any element associated with a url, does this not work for you when loading the css stylesheet? http://api.jquery.com/load-event/

Try something like this:

var path = $(this).attr('href');
$('head link').remove();
var styleSheet = $('<link type="text/css" href="'+path+'" rel="stylesheet" />');
styleSheet.load(function(){alert("Loaded");});
$('head').append(styleSheet);

Edit: As pointed out below this only works in IE, who would have thought?

Solution 3:

var cssLoaded = function()
{
    alert($('body').css('background-color'));
};
$('#theme-selector a').click(function(){
   var path = $(this).attr('href');
   $('head link').remove();
   $('head').append('<link onload="cssLoaded();" type="text/css" href="'+path+'" rel="stylesheet" />');
   return false;
});

successfully tested in Chrome 28, IE 10, FF22

Solution 4:

You could use lazyload (jQuery plugin) to load a css file.
It has the ability to call a function when the file is included.

Example:

// Load a CSS file and pass an argument to the callback function.
LazyLoad.css('foo.css', function (arg) {
  // put your code here
});

Solution 5:

Got here looking for a way to remove critical CSS ( element) after being 100% sure, that external sheets have lazyloaded and rendered. This would allow me to use universal, yet visually pleasing critical internal CSS globally over several projects.
Since some of the critical styles go visually against the lazyloaded ones, so they need to be overridden (too much work), or removed. This is what I want, in short:

  1. Load the document with critical internal CSS
  2. Lazyload the additional CSS after the document is rendered and interactive (good for SEO and UX)
  3. Remove critical CSS from HTML after the fancy additional stylesheets have been loaded and truly rendered, to prevent flickering which occured with all other solutions (I have tested this a lot).
Related:  Javascript Set vs. Array performance

A 100% working solution (may it be unpopular) is to use setInterval(); after having the secondary css lazyloaded, to periodically check, whether a style, unique to secondary CSS has truly been applied. Then I can have the critical CSS removed (or whatever I want to do..).

I have created a live demo with comments on Codepen: https://codepen.io/Marko36/pen/YjzQzd and some info in a blogpost: Triggering a Javascript/jQuery event after CSS has loaded.

var CSSloadcheck = setInterval(function () {
    if ($('body').css('opacity') != 1) {
    //when opacity is set to 0.99 by external sheet
      $('style#critical').remove();
      clearInterval(CSSloadcheck);  
  }
}, 100);

Solution 6:

You could simply keep on checking if the background colour is still the same, and then do your thing if ever it changes.

oldbackground=getbackground()
function checkbackground(){
    if(oldbackground!=getbackground()){
        oldbackground=getbackground()
        //Do your thing
    }
}
setInterval(checkbackground,100)

References