-
-
Save stramel/91d05253f801f771da38b3bc7d3c765f to your computer and use it in GitHub Desktop.
/* | |
TODO: | |
X Maybe account for defaults: color: var(--header-color, blue); | |
- Verify cross domain working or not (it is working from dropbox) | |
- Option to wait to apply anything until all <link>s are parsed or inject what we have and update as each <link> returns | |
- Need to test on a more complex CSS file | |
- Option to save parsed file in local/session storage so there isn't a delay on additional page loads. Could only do it for links (with URLs to use as keys) and style blocks with IDs of some sort | |
- Need to test more complex values like rgba(255,0,0,0.5); and something with !important | |
- Try multiple links | |
- Local links | |
- Ajax driven site, or CSS added later the top of the stack | |
*/ | |
let cssVarPoly = { | |
init() { | |
// first lets see if the browser supports CSS variables | |
// No version of IE supports window.CSS.supports, so if that isn't supported in the first place we know CSS variables is not supported | |
// Edge supports supports, so check for actual variable support | |
if (window.CSS && window.CSS.supports && window.CSS.supports('(--foo: red)')) { | |
// this browser does support variables, abort | |
console.log('your browser supports CSS variables, aborting and letting the native support handle things.'); | |
return; | |
} else { | |
// edge barfs on console statements if the console is not open... lame! | |
console.log('no support for you! polyfill all (some of) the things!!'); | |
document.querySelector('body').classList.add('cssvars-polyfilled'); | |
} | |
cssVarPoly.ratifiedVars = {}; | |
cssVarPoly.varsByBlock = {}; | |
cssVarPoly.oldCSS = {}; | |
// start things off | |
cssVarPoly.findCSS(); | |
cssVarPoly.updateCSS(); | |
}, | |
// find all the css blocks, save off the content, and look for variables | |
findCSS() { | |
let styleBlocks = document.querySelectorAll('style:not(.inserted),link[type="text/css"]'); | |
// we need to track the order of the style/link elements when we save off the CSS, set a counter | |
let counter = 1; | |
// loop through all CSS blocks looking for CSS variables being set | |
[].forEach.call(styleBlocks, function(block) { | |
// console.log(block.nodeName); | |
let theCSS; | |
if (block.nodeName === 'STYLE') { | |
// console.log("style"); | |
theCSS = block.innerHTML; | |
cssVarPoly.findSetters(theCSS, counter); | |
} else if (block.nodeName === 'LINK') { | |
// console.log("link"); | |
cssVarPoly.getLink(block.getAttribute('href'), counter, function(counter, request) { | |
cssVarPoly.findSetters(request.responseText, counter); | |
cssVarPoly.oldCSS[counter] = request.responseText; | |
cssVarPoly.updateCSS(); | |
}); | |
theCSS = ''; | |
} | |
// save off the CSS to parse through again later. the value may be empty for links that are waiting for their ajax return, but this will maintain the order | |
cssVarPoly.oldCSS[counter] = theCSS; | |
counter++; | |
}); | |
}, | |
// find all the "--variable: value" matches in a provided block of CSS and add them to the master list | |
findSetters(theCSS, counter) { | |
// console.log(theCSS); | |
cssVarPoly.varsByBlock[counter] = theCSS.match(/(--.+:.+;)/g); | |
}, | |
// run through all the CSS blocks to update the variables and then inject on the page | |
updateCSS() { | |
// first lets loop through all the variables to make sure later vars trump earlier vars | |
cssVarPoly.ratifySetters(cssVarPoly.varsByBlock); | |
// loop through the css blocks (styles and links) | |
for (let curCSSID in cssVarPoly.oldCSS) { | |
// console.log("curCSS:",oldCSS[curCSSID]); | |
let newCSS = cssVarPoly.replaceGetters(cssVarPoly.oldCSS[curCSSID], cssVarPoly.ratifiedVars); | |
// put it back into the page | |
// first check to see if this block exists already | |
if (document.querySelector('#inserted' + curCSSID)) { | |
// console.log("updating") | |
document.querySelector('#inserted' + curCSSID).innerHTML = newCSS; | |
} else { | |
// console.log("adding"); | |
var style = document.createElement('style'); | |
style.type = 'text/css'; | |
style.innerHTML = newCSS; | |
style.classList.add('inserted'); | |
style.id = 'inserted' + curCSSID; | |
document.getElementsByTagName('head')[0].appendChild(style); | |
} | |
}; | |
}, | |
// parse a provided block of CSS looking for a provided list of variables and replace the --var-name with the correct value | |
replaceGetters(curCSS, varList) { | |
// console.log(varList); | |
for (let theVar in varList) { | |
// console.log(theVar); | |
// match the variable with the actual variable name | |
let getterRegex = new RegExp('var\\(\\s*' + theVar + '\\s*\\)', 'g'); | |
// console.log(getterRegex); | |
// console.log(curCSS); | |
curCSS = curCSS.replace(getterRegex, varList[theVar]); | |
// now check for any getters that are left that have fallbacks | |
let getterRegex2 = new RegExp('var\\(\\s*.+\\s*,\\s*(.+)\\)', 'g'); | |
// console.log(getterRegex); | |
// console.log(curCSS); | |
let matches = curCSS.match(getterRegex2); | |
if (matches) { | |
// console.log("matches",matches); | |
matches.forEach(function(match) { | |
// console.log(match.match(/var\(.+,\s*(.+)\)/)) | |
// find the fallback within the getter | |
curCSS = curCSS.replace(match, match.match(/var\(.+,\s*(.+)\)/)[1]); | |
}); | |
} | |
// curCSS = curCSS.replace(getterRegex2,varList[theVar]); | |
}; | |
// console.log(curCSS); | |
return curCSS; | |
}, | |
// determine the css variable name value pair and track the latest | |
ratifySetters(varList) { | |
// console.log("varList:",varList); | |
// loop through each block in order, to maintain order specificity | |
for (let curBlock in varList) { | |
let curVars = varList[curBlock]; | |
// console.log("curVars:",curVars); | |
// loop through each var in the block | |
curVars.forEach(function(theVar) { | |
// console.log(theVar); | |
// split on the name value pair separator | |
let matches = theVar.split(/:\s*/); | |
// console.log(matches); | |
// put it in an object based on the varName. Each time we do this it will override a previous use and so will always have the last set be the winner | |
// 0 = the name, 1 = the value, strip off the ; if it is there | |
cssVarPoly.ratifiedVars[matches[0]] = matches[1].replace(/;/, ''); | |
}); | |
}; | |
// console.log(ratifiedVars); | |
}, | |
// get the CSS file (same domain for now) | |
getLink(url, counter, success) { | |
var request = new XMLHttpRequest(); | |
request.open('GET', url, true); | |
request.overrideMimeType('text/css;'); | |
request.onload = function() { | |
if (request.status >= 200 && request.status < 400) { | |
// Success! | |
// console.log(request.responseText); | |
if (typeof success === 'function') { | |
success(counter, request); | |
} | |
} else { | |
// We reached our target server, but it returned an error | |
console.warn('an error was returned from:', url); | |
} | |
}; | |
request.onerror = function() { | |
// There was a connection error of some sort | |
console.warn('we could not get anything from:', url); | |
}; | |
request.send(); | |
} | |
}; | |
// hash = function(s){ | |
// return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); | |
// } | |
cssVarPoly.init(); | |
// export default makeFit; | |
// stuff for hiding documentation for Opera Mini testing | |
document.querySelector('.hide-docs').addEventListener('click',function(event){ | |
event.preventDefault(); | |
document.querySelector('body').classList.toggle('hide-the-docs'); | |
}); |
does not work for @import
rules. Is there a reason why its not simply using document.styleSheets
?
I had no joy with this in IE 11. The console said it had to do something with line 14, so I changed it to init: function () {
and that fixed it for me.
I'm the original author of the codepen. I have copied the polyfill into a repo so others can help with it. I have applied the fix from @gentle-media and logged the issue from @loominade as it is a bit bigger of an update.
https://github.com/aaronbarker/css-variables-polyfill
Thanks!
I hope referencing another library here isn't considered poor form, but doing so may help others searching for more robust solution.
- GitHub: https://github.com/jhildenbiddle/css-vars-ponyfill
- Demo : https://codepen.io/jhildenbiddle/pen/ZxYJrR
Long story short, I too stumbled on this gist after searching for a way to support CSS custom properties in legacy browsers. The limitations made this a no-go for me, so I created css-vars-ponyfill. I also needed to dynamically update property values on the client (not just do a one-time conversion to static values) which this library also handles.
Hope this helps someone, and hope you don't mind the link @aaronbarker!
another polyfill for ie11
https://github.com/nuxodin/ie11CustomProperties
Original: http://codepen.io/aaronbarker/pen/MeaRmL