Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active July 28, 2020 23:28
Show Gist options
  • Select an option

  • Save dfkaye/4773010 to your computer and use it in GitHub Desktop.

Select an option

Save dfkaye/4773010 to your computer and use it in GitHub Desktop.
requestCss.js - stylesheet loader api for javaScript - attempts to work around lack-of-support for css load events && the rule number limits in MSIE
/**
* file: css-api.js - provides stylesheet requestCss api to JavaScript -
* author: @dfkaye - david.kaye
* date: 2013-2-12
* fixed whitespace: 2020-07-28
*
* Prior Art:
* - http://www.phpied.com/when-is-a-stylesheet-really-loaded/
* - http://www.zachleat.com/web/load-css-dynamically/
*
* To-DO
* - commonjs module support for global scope and exports
* - better (any) negative tests for bad URLs
*
*/
(function (exports) {
/* public */
exports.requestCss = requestCss;
/* local */
var requested = {};
/*
* params - any number of string arguments to css filepaths.
* The optional callback function should be the last argument.
*/
function requestCss() {
/*
* <link> elements don't fire load event cross-browser
* (webkit, FF < 9 - opera uses addEventListener...),
* plus IE restricts <link> and @import counts to 31, nesting 3 deep, etc.
* BUT, <style> elements fire load events!
* AND, we can use multiple imports in a <style> to beat the IE restriction (no kidding!).
*/
var style = document.createElement('style');
style.setAttribute('media', 'all');
var args = arguments;
var len = args.length;
var callback = args[len - 1];
if (typeof callback === 'function') {
len = len - 1;
style.onload = function () {
style.onload = null;
callback();
};
}
var pending = len;
var cssText = '';
// Append the element right away so that the @import directive runs on an
// active element; borks out otherwise.
document.getElementsByTagName('head')[0].appendChild(style);
for (var i = 0; i < len; i++) {
var url = args[i];
if (typeof url == 'string' && !(url in requested)) {
requested[url] = url;
try {
cssText += "\n@import url(" + url + ");";
} catch (err) {
console.error(err + ': ' + url);
} finally {
continue;
}
}
}
// try not to block other processes
setTimeout(function () {
if (style.styleSheet) {
// internet explorer
style.styleSheet.cssText = cssText;
} else {
// most DOM-compliant browsers
style.appendChild(document.createTextNode(cssText));
}
}, 0);
};
}(this));
@dfkaye

dfkaye commented Jul 22, 2013

Copy link
Copy Markdown
Author

STATUS as of 22 JUL 2013

I've added a test repo here => https://github.com/dfkaye/css-request-test/ - taking the cuzillion test cases you put up on jsbin. You can view the rawgithub page in action here => http://rawgithub.com/dfkaye/css-request-test/master/index.html

So far looks like firefox does it right. I'm checking other rules or attributes in chrome which seems to load 'done' eagerly. More to come.

That cuzillion delay is definitely a pain - it ends up aborting in MSIE 10 and various compat modes for me - I'll see if I can figure out how to assign a real "done" property that the callback can check...

There's already something wrong when we're making 32 requests to load into a single stylesheet. The point of this lib was to load an arbitrary number of style tags with a manageable number of imports (like 12).

MORE TO COME (LATER TONIGHT)....

@dfkaye

dfkaye commented Jul 23, 2013

Copy link
Copy Markdown
Author

"Uncle." - loading multiple delayed css in imports in a single style tag has uncannily blocking behavior in IE, callsback eagerly in Chrome but before the style is actually applied, blows up in Firefox unless you use try/catch for the style.sheet.cssRules read which is not accessible for cross-domain css, and never fires the final callback in Opera.

From my perspective, however, IE has this correct and all the others are off the mark.

To give IE a break from blocking imports, I've redone the repo example with link tags instead of style tags plus imports, and use the img prefetch trick by stoyan stefanov. All 4 browsers seem to fire both callbacks after the second stylesheet arrives and the rules are applied.

repo: https://github.com/dfkaye/css-request-test/

test page: http://rawgithub.com/dfkaye/css-request-test/master/index.html

using js file at https://github.com/dfkaye/css-request-test/blob/master/js/img-css-request.js

@dfkaye

dfkaye commented Jul 23, 2013

Copy link
Copy Markdown
Author

Updated - fallback file for IE9-- uses style/import strategy, the rest use link strategy - see test page for latest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment