Last active
July 28, 2020 23:28
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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)); |
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
"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