IE11 - CSS 变量是否存在 polyfill/脚本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46429937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
IE11 - does a polyfill / script exist for CSS variables?
提问by R. StackUser
I'm developing a webpage in a mixed web browser environment (Chrome/IE11). IE11 doesn't support CSS variables, is there a polyfill or script that exists that would allow me to use CSS variables in IE11?
我正在混合 Web 浏览器环境 (Chrome/IE11) 中开发网页。IE11 不支持 CSS 变量,是否存在允许我在 IE11 中使用 CSS 变量的 polyfill 或脚本?
回答by jhildenbiddle
Yes, so long as you're processing root-level custom properties (IE9+).
是的,只要您正在处理根级自定义属性 (IE9+)。
- GitHub: https://github.com/jhildenbiddle/css-vars-ponyfill
- NPM: https://www.npmjs.com/package/css-vars-ponyfill
- Demo: https://codepen.io/jhildenbiddle/pen/ZxYJrR
- GitHub: https://github.com/jhildenbiddle/css-vars-ponyfill
- NPM:https: //www.npmjs.com/package/css-vars-ponyfill
- 演示:https: //codepen.io/jhildenbiddle/pen/ZxYJrR
From the README:
从自述文件:
Features
- Client-side transformation of CSS custom properties to static values
- Live updates of runtime values in both modern and legacy browsers
- Transforms
<link>
,<style>
, and@import
CSS- Transforms relative
url()
paths to absolute URLs- Supports chained and nested
var()
functions- Supports
var()
function fallback values- Supports web components / shadow DOM CSS
- Watch mode auto-updates on
<link>
and<style>
changes- UMD and ES6 module available
- TypeScript definitions included
- Lightweight (6k min+gzip) and dependency-free
Limitations
- Custom property support is limited to
:root
and:host
declarations- The use of var() is limited to property values (per W3C specification)
特征
- CSS 自定义属性到静态值的客户端转换
- 在现代和传统浏览器中实时更新运行时值
- 变换
<link>
,<style>
和@import
CSS- 将相对
url()
路径转换为绝对 URL- 支持链式和嵌套
var()
函数- 支持
var()
函数回退值- 支持 web 组件/shadow DOM CSS
- 观看模式自动更新
<link>
和<style>
更改- 提供 UMD 和 ES6 模块
- 包括 TypeScript 定义
- 轻量级(6k min+gzip)且无依赖
限制
- 自定义属性支持仅限于
:root
和:host
声明- var() 的使用仅限于属性值(根据W3C 规范)
Here are a few examples of what the library can handle:
以下是库可以处理的一些示例:
Root-level custom properties
根级自定义属性
:root {
--a: red;
}
p {
color: var(--a);
}
Chained custom properties
链式自定义属性
:root {
--a: var(--b);
--b: var(--c);
--c: red;
}
p {
color: var(--a);
}
Nested custom properties
嵌套的自定义属性
:root {
--a: 1em;
--b: 2;
}
p {
font-size: calc(var(--a) * var(--b));
}
Fallback values
回退值
p {
font-size: var(--a, 1rem);
color: var(--b, var(--c, var(--d, red)));
}
Transforms <link>
, <style>
, and @import
CSS
变换<link>
,<style>
和@import
CSS
<link rel="stylesheet" href="/absolute/path/to/style.css">
<link rel="stylesheet" href="../relative/path/to/style.css">
<style>
@import "/absolute/path/to/style.css";
@import "../relative/path/to/style.css";
</style>
Transforms web components / shadow DOM
转换 Web 组件/影子 DOM
<custom-element>
#shadow-root
<style>
.my-custom-element {
color: var(--test-color);
}
</style>
<div class="my-custom-element">Hello.</div>
</custom-element>
For the sake of completeness: w3c specs
为了完整起见:w3c 规范
Hope this helps.
希望这可以帮助。
(Shameless self-promotion: Check)
(无耻的自我推销:打勾)
回答by Tobias Buschor
This polyfill enables almost complete support for Custom Properties (not only root-level) in IE11:
https://github.com/nuxodin/ie11CustomProperties
这个 polyfill 几乎完全支持IE11 中的自定义属性(不仅是根级):https:
//github.com/nuxodin/ie11CustomProperties
How it works
这个怎么运作
The script makes use of the fact that IE has minimal custom properties support where properties can be defined and read out with the cascade in mind..myEl {-ie-test:'aaa'} // only one dash allowed! "-"
then read it in javascript:getComputedStyle( querySelector('.myEl') )['-ie-test']
该脚本利用了这样一个事实,即 IE 具有最少的自定义属性支持,其中可以在考虑级联的情况下定义和读取属性。.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
然后在javascript中阅读它:getComputedStyle( querySelector('.myEl') )['-ie-test']
Features from the README:
自述文件的功能:
- handles dynamic added html-content
- handles dynamic added
<style>
,<link>
-elements- chaining
--bar:var(--foo)
- fallback
var(--color, blue)
- :focus, :target, :hover
- js-integration:
style.setProperty('--x','y')
style.getPropertyValue('--x')
getComputedStyle(el).getPropertyValue('--inherited')
- Inline styles:
<div ie-style="--color:blue"...
- cascade works
- inheritance works
- under 3k (min+gzip) and dependency-free
- 处理动态添加的 html 内容
- 处理动态添加的
<style>
,<link>
-elements- 链接
--bar:var(--foo)
- 倒退
var(--color, blue)
- :focus, :target, :hover
- js集成:
style.setProperty('--x','y')
style.getPropertyValue('--x')
getComputedStyle(el).getPropertyValue('--inherited')
- 内联样式:
<div ie-style="--color:blue"...
- 级联工程
- 传承作品
- 低于 3k (min+gzip) 且无依赖
Demo:
演示:
回答by ajawad987
+1 for the code-pen snippet link in the question comment section above by [I has kode]. One thing I found though is the snippet needs to be slightly modified to have the function declarations defined in the JSON format for IE11 to not complain. Below is the slightly modified version of the code pen snippet:
+1 为 [I have kode] 上面问题评论部分中的代码笔片段链接。我发现的一件事是需要稍微修改代码段,以使 IE11 的 JSON 格式定义的函数声明不会抱怨。下面是代码笔片段的略微修改版本:
let cssVarPoly = {
init: function() {
// 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: function() {
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: function(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: function() {
// 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: function(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: function(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: function(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();
}
};
cssVarPoly.init();
回答by Grumpy Old Bastard
I tried this version of Polyfill but ended up with errors when one line in CSS had multiple variables (FI font and color). A colleague of mine helped me out. See line 94.
我尝试了这个版本的 Polyfill,但是当 CSS 中的一行有多个变量(FI 字体和颜色)时,最终出现错误。我的一个同事帮了我一把。见第 94 行。
let cssVarPoly = {
init: function() {
// 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: function() {
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: function(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: function() {
// 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: function(curCSS, varList) {
// console.log(varList);
for (let theVar in varList) {
// console.log(theVar);
// match the variable with the actual variable name
// console.log (theVar);
var res = theVar.match(/--[a-zA-Z0-9-]+/g);
// console.log (res[0]);
theVar = res[0];
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: function(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: function(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();
}
};
cssVarPoly.init();