IE11 - có tồn tại polyfill / script cho các biến CSS không?


91

Tôi đang phát triển một trang web trong môi trường trình duyệt web hỗn hợp (Chrome / IE11). IE11 không hỗ trợ các biến CSS, có polyfill hoặc script nào tồn tại cho phép tôi sử dụng các biến CSS trong IE11 không?


Những loại biến css?
bhansa


@ R.StackUser Do đánh dấu một trong các câu trả lời dưới đây là câu đúng. Chúc mừng.
AndrewL64

Có một cái nhìn tại này Custom-Properties-Polyfill: github.com/nuxodin/ie11CustomProperties
Tobias Buschor

Câu trả lời:


113

Có, miễn là bạn đang xử lý các thuộc tính tùy chỉnh cấp gốc (IE9 +).

Từ README:

Đặc trưng

  • Chuyển đổi phía máy khách của các thuộc tính tùy chỉnh CSS thành các giá trị tĩnh
  • Cập nhật trực tiếp các giá trị thời gian chạy trong cả trình duyệt hiện đại và cũ
  • Biến đổi <link>, <style>@importCSS
  • Chuyển đổi url()đường dẫn tương đối thành URL tuyệt đối
  • Hỗ trợ các var()hàm được xâu chuỗi và lồng nhau
  • Hỗ trợ var()các giá trị dự phòng của hàm
  • Hỗ trợ các thành phần web / CSS DOM bóng
  • Chế độ xem tự động cập nhật <link><style>thay đổi
  • Mô-đun UMD và ES6 có sẵn
  • Định nghĩa TypeScript bao gồm
  • Nhẹ (6k min + gzip) và không phụ thuộc

Hạn chế

  • Hỗ trợ thuộc tính tùy chỉnh được giới hạn ở :rootvà các :hostkhai báo
  • Việc sử dụng var () bị giới hạn ở các giá trị thuộc tính (theo đặc điểm kỹ thuật W3C )

Dưới đây là một vài ví dụ về những gì thư viện có thể xử lý:

Thuộc tính tùy chỉnh cấp gốc

:root {
    --a: red;
}

p {
    color: var(--a);
}

Thuộc tính tùy chỉnh theo chuỗi

:root {
    --a: var(--b);
    --b: var(--c);
    --c: red;
}

p {
    color: var(--a);
}

Thuộc tính tùy chỉnh lồng nhau

:root {
    --a: 1em;
    --b: 2;
}

p {
    font-size: calc(var(--a) * var(--b));
}

Giá trị dự phòng

p {
    font-size: var(--a, 1rem);
    color: var(--b, var(--c, var(--d, red))); 
}

Biến đổi <link>, <style>@importCSS

<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>

Chuyển đổi các thành phần web / Shadow DOM

<custom-element>
  #shadow-root
    <style>
      .my-custom-element {
        color: var(--test-color);
      }
    </style>
    <div class="my-custom-element">Hello.</div>
</custom-element>

Vì lợi ích của sự hoàn chỉnh: thông số kỹ thuật w3c

Hi vọng điêu nay co ich.

(Tự quảng cáo không biết xấu hổ: Kiểm tra)


6
Đây phải là câu trả lời được chấp nhận. Không chỉ codepen thiếu các tính năng mà còn không thể xử lý những thứ như css thu nhỏ, biến ảnh nền, nhận xét trong css, v.v. Tôi biết vì tôi đã thử nghiệm rộng rãi nó. Tôi khuyên bạn nên sử dụng ponyfill từ @jhildenbiddle
Andres M

Thông minh! Cảm ơn bạn!
Tackgnol

1
@Davey - Ponyfill không hỗ trợ các thuộc tính tùy chỉnh theo phạm vi, vì vậy, --primary: #aaakhai báo sẽ không được xử lý. Giải thích chi tiết hơn được cung cấp trong vấn đề này: Hỗ trợ mở rộng bên ngoài: root .
jhildenbiddle 14/02/19

2
@Davey trong IE bạn có thể truy cập giá trị của thuộc tính tùy chỉnh nhưng không bắt đầu bằng "-". Thats cách thức hoạt động của polyfill của tôi, xem stackoverflow.com/a/57000437/4865307
Tobias Buschor

1
FYI, tôi thấy điều này nhanh hơn nhiều so với giải pháp thay thế (tức là11CustomProperties) - :rootgiới hạn không phải là vấn đề đối với tôi. Đối với tăng hiệu suất hơn nữa, hãy kiểm tra các tùy chọn, ví dụ { exclude: '[href*=jquery-ui],...', preserveStatic: false }.
Dunc

62

Polyfill này cho phép hỗ trợ gần như hoàn chỉnh cho Thuộc tính tùy chỉnh ( không chỉ ở cấp gốc ) trong IE11:
https://github.com/nuxodin/ie11CustomProperties

Làm thế nào nó hoạt động

Tập lệnh sử dụng thực tế là IE có hỗ trợ các thuộc tính tùy chỉnh tối thiểu, nơi các thuộc tính có thể được xác định và đọc ra trong tâm trí.
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
sau đó đọc nó bằng javascript:
getComputedStyle( querySelector('.myEl') )['-ie-test']

Các tính năng từ README:

  • xử lý nội dung html được thêm động
  • xử lý động thêm <style>, <link>-elements
  • xâu chuỗi --bar:var(--foo)
  • dự phòng var(--color, blue)
  • : focus,: target,: hover
  • tích hợp js:
    • style.setProperty('--x','y')
    • style.getPropertyValue('--x')
    • getComputedStyle(el).getPropertyValue('--inherited')
  • Kiểu nội tuyến: <div ie-style="--color:blue"...
  • công trình thác
  • công việc thừa kế
  • dưới 3k (min + gzip) và không phụ thuộc

Bản giới thiệu:

https://rawcdn.githack.com/nuxodin/ie11CustomProperties/b851ec2b6b8e336a78857b570d9c12a8526c9a91/test.html


1
Tôi đã mất một thời gian để hiểu cách sử dụng polyfill này. README.md không rõ ràng lắm về nó. Giải pháp: bạn chỉ cần thêm <script src="yourJsPath/ie11CustomProperties.js"></script>vào phần đầu của tệp HTML và IE11 sẽ đồng thời.
Jpsy

1
Cảm ơn phản hôi của bạn. Bây giờ có một ussage-section
Tobias Buschor

3
Đối với tôi, giải pháp thon gọn hơn nhiều này là cách tiếp cận đúng đắn. Ponyfill ở trên chỉ được đánh giá cao hơn vì tồn tại sớm hơn (Cam kết đầu tiên vào tháng 11 năm 2017), trong khi ie11CustomProperties được cam kết lần đầu vào tháng 7 năm 2019). Đánh giá bản thân. KHÔNG LẤY SỐ phiếu bầu CAO HƠN ĐỂ "CHẤT LƯỢNG TỐT HƠN".
digitaldonkey

9

+1 cho liên kết đoạn mã bút trong phần nhận xét câu hỏi ở trên bởi [Tôi có kode]. Tuy nhiên, tôi nhận thấy một điều là đoạn mã cần được sửa đổi một chút để có các khai báo hàm được xác định ở định dạng JSON để IE11 không bị phàn nàn. Dưới đây là phiên bản sửa đổi một chút của đoạn mã bút:

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();

3

Tôi đã thử phiên bản Polyfill này nhưng cuối cùng vẫn gặp lỗi khi một dòng trong CSS có nhiều biến (phông chữ và màu FI). Một đồng nghiệp của tôi đã giúp tôi. Xem dòng 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();

0

Để hỗ trợ Internet Explorer, Chỉ cần sử dụng tập lệnh dưới đây trong thẻ head index.html và nó hoạt động như một sự quyến rũ.

<script>window.MSInputMethodContext && document.documentMode && document.write('<script src="https://cdn.jsdelivr.net/gh/nuxodin/ie11CustomProperties@4.1.0/ie11CustomProperties.min.js"><\x2fscript>');</script>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.