21

I want to use jQuery to asynchronously load CSS for a document.

I found this sample, but this doesn't seem to work in IE:

<script type="text/javascript" src="/inc/body/jquery/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
    $(function(){
        $('<link>', {
            rel: 'stylesheet',
            type: 'text/css',
            href: '/inc/body/jquery/css/start/jquery-ui-1.8.10.custom.css'
        }).appendTo('head');
        $.getScript("/inc/body/jquery/js/jquery-ui-1.8.10.custom.min.js", function(){
        });
    });
</script>

Basically I want to load jQuery UI after the all other data, images, styles, etc load to the page.

The $.getScript works great for JS file. Only problem is with CSS in IE.

Do you know a better solution?

gailbear
  • 519
  • 3
  • 13
Adam Lukaszczyk
  • 4,898
  • 3
  • 22
  • 22

8 Answers8

43

Here's a method for asynchronous stylesheet loading that doesn't block page render that worked for me:

https://github.com/filamentgroup/loadCSS/blob/master/loadCSS.js

Reduced example of the code linked above, based on lonesomeday's answer

var stylesheet = document.createElement('link');
stylesheet.href = '/inc/body/jquery/css/start/jquery-ui-1.8.10.custom.css';
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
// temporarily set media to something inapplicable to ensure it'll fetch without blocking render
stylesheet.media = 'only x';
// set the media back when the stylesheet loads
stylesheet.onload = function() {stylesheet.media = 'all'}
document.getElementsByTagName('head')[0].appendChild(stylesheet);
Dmitry Pashkevich
  • 13,431
  • 9
  • 55
  • 73
31

The safe way is the old way...

var stylesheet = document.createElement('link');
stylesheet.href = '/inc/body/jquery/css/start/jquery-ui-1.8.10.custom.css';
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
Mark Coleman
  • 40,542
  • 9
  • 81
  • 101
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
  • 1
    Thanks, but I'd rather prefer to do this in jQuery. – Adam Lukaszczyk Mar 03 '11 at 21:37
  • 5
    Why is this preferable to jQuery? You mention this is the "safe" way. What makes it safer than the accepted answer (assuming of course that jQuery is present)? – Tom Auger Dec 01 '11 at 18:08
  • 1
    RequireJS.org docs specifically refer to this approach: http://requirejs.org/docs/faq-advanced.html#css – Hendy Irawan Aug 20 '12 at 11:29
  • 4
    As a rule of thumb: Pure JS is always better, but I don't see how this solution solves the issue of not knowing when the CSS file has finished loading. – Stephan Kristyn Sep 08 '13 at 04:05
  • 5
    Let me tell you why this approach is more efficient than jQuery... Its because if you load it via jQuery, you will have to wait until jQuery is loaded but with this approach you won't need to wait for jQuery and you can load jQuery, CSS and other scripts in parallel – Abhishek Goel Apr 25 '14 at 08:11
  • 1
    @AbhishekGoel A key aspect to asynchronous loading is pushing content back in the load order so the critical stuff can load sooner. Thus having it load after jQuery could be desirable, as it is in my case. – andrewb Jun 24 '15 at 01:18
20

This should work in IE:

$("head").append("<link rel='stylesheet' type='text/css' href='/inc/body/jquery/css/start/jquery-ui-1.8.10.custom.css' />");
Peter Olson
  • 139,199
  • 49
  • 202
  • 242
  • 7
    The reverse should work, as well: `$('').appendTo($('head'))`. This would allow you to chain the `link` element, rather than the `head` element, if you wanted to do something else with it after appending it to ``. – Zenexer Jul 16 '13 at 00:49
  • 7
    According to this (http://stackoverflow.com/questions/5085228/does-jquery-append-behave-asynchronously), append does NOT behave asynchronously. – ElHaix Jul 26 '13 at 02:43
  • 1
    @ElHaix That's true, but I think the OP misunderstood the word "asynchronously" and really meant "dynamically". – Peter Olson Jul 26 '13 at 03:17
  • @PeterOlson - Looking at http://www.yterium.net/jQl-an-asynchronous-jQuery-Loader - could you actually load up your CSS asynch? – ElHaix Jul 26 '13 at 13:05
  • 1
    Right, this is not asynchronous. – Adam Grant Nov 08 '13 at 15:38
  • @Dobiatowski If you decided to use jQuery, then don't forget to add the cache: true parameter so that the client doesn't load the content on every page load. – Sceptical Jule Aug 12 '14 at 23:33
  • @PeterOlson, @ajkochanowicz It's still asynchronous, because the loading happens in parallel to the loading of the other CSS files and JS files. It just so happens that there is no `async` attribute yet so the only way to achieve this is with Javascript. Perhaps 'non-render-blocking' is a better term. – Chloe May 25 '15 at 05:28
10

As mentioned in RequireJS docs, the tricky part lies not in loading the CSS:

function loadCss(url) {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}

but in knowing when/whether the CSS has loaded successfully, as in your use case " I want to load jQuery UI after the all other data, images, styles, etc load".

Ideally RequireJS could load CSS files as dependencies. However, there are issues knowing when a CSS file has been loaded, particularly in Gecko/Firefox when the file is loaded from another domain. Some history can be found in this Dojo ticket.

Knowing when the file is loaded is important because you may only want to grab the dimensions of a DOM element once the style sheet has loaded.

Some people have implemented an approach where they look for a well known style to be applied to a specific HTML element to know if a style sheet is loaded. Due to the specificity of that solution, it is not something that would fit will with RequireJS. Knowing when the link element has loaded the referenced file would be the most robust solution.

Since knowing when the file has loaded is not reliable, it does not make sense to explicitly support CSS files in RequireJS loading, since it will lead to bug reports due to browser behavior.

Hendy Irawan
  • 20,498
  • 11
  • 103
  • 114
1

As per Dynamically loading css stylesheet doesn't work on IE:

You need to set the href attr last and only after the link elem is appended to the head.

$("<link>")
  .appendTo('head')
  .attr({type : 'text/css', rel : 'stylesheet'})
  .attr('href', '/css/your_css_file.css');
Community
  • 1
  • 1
ekerner
  • 5,650
  • 1
  • 37
  • 31
0
$.get("path.to.css",function(data){
    $("head").append("<style>"+data+"</style>");
});
noamtcohen
  • 4,432
  • 2
  • 20
  • 14
0

None of the solutions here actually load the CSS file without blocking page render - which is typically what is meant by “asynchronously.” (If the browser is waiting for something and preventing the user from interacting with the page, the situation is by definition synchronous.)

Examples of synchronous and asynchronous loading can be found here:

http://ajh.us/async-css

I have found that using a setTimeout to defer loading seems to help.

Alan H.
  • 16,219
  • 17
  • 80
  • 113
0
jQuery(function(){

jQuery('head').append('<link href="/inc/body/jquery/css/start/jquery-ui-1.8.10.custom.css" rel="stylesheet" type="text/css" />')

});
Praveen Prasad
  • 31,561
  • 18
  • 73
  • 106