IE11 - มี polyfill / script สำหรับตัวแปร CSS หรือไม่


93

ฉันกำลังพัฒนาหน้าเว็บในสภาพแวดล้อมเว็บเบราว์เซอร์แบบผสม (Chrome / IE11) IE11 ไม่รองรับตัวแปร CSS มีโพลีฟิลล์หรือสคริปต์ที่อนุญาตให้ฉันใช้ตัวแปร CSS ใน IE11 หรือไม่


ตัวแปร css แบบไหน?
bhansa


@ R.StackUser ทำเครื่องหมายหนึ่งในคำตอบด้านล่างว่าเป็นคำตอบที่ถูกต้อง ไชโย
AndrewL64

ดู Custom-Properties-Polyfill นี้: github.com/nuxodin/ie11CustomProperties
Tobias Buschor

คำตอบ:


114

ใช่ตราบใดที่คุณกำลังประมวลผลคุณสมบัติแบบกำหนดเองระดับรูท (IE9 +)

จาก README:

คุณสมบัติ

  • การแปลงคุณสมบัติที่กำหนดเองของ CSS เป็นค่าคงที่
  • การอัปเดตค่ารันไทม์แบบสดทั้งในเบราว์เซอร์รุ่นใหม่และเบราว์เซอร์รุ่นเก่า
  • แปลง<link>, <style>และ@importCSS
  • แปลงurl()เส้นทางสัมพัทธ์เป็น URL ที่สมบูรณ์
  • รองรับvar()ฟังก์ชันที่ถูกล่ามโซ่และซ้อนกัน
  • รองรับvar()ค่าทางเลือกของฟังก์ชัน
  • รองรับส่วนประกอบของเว็บ / Shadow DOM CSS
  • โหมดนาฬิกาอัปเดตอัตโนมัติ<link>และ<style>การเปลี่ยนแปลง
  • มีโมดูล UMD และ ES6
  • รวมนิยาม TypeScript
  • น้ำหนักเบา (6k นาที + gzip) และปราศจากการพึ่งพา

ข้อ จำกัด

  • การสนับสนุนคุณสมบัติแบบกำหนดเองถูก จำกัด ไว้ที่:rootและ:hostการประกาศ
  • การใช้ var () ถูก จำกัด ไว้ที่ค่าคุณสมบัติ (ตามข้อกำหนด W3C )

นี่คือตัวอย่างบางส่วนของสิ่งที่ไลบรารีสามารถจัดการได้:

คุณสมบัติแบบกำหนดเองระดับรูท

:root {
    --a: red;
}

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

คุณสมบัติแบบกำหนดเองที่ถูกล่ามโซ่

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

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

คุณสมบัติที่กำหนดเองที่ซ้อนกัน

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

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

ค่าทางเลือก

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

แปลง<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>

แปลงส่วนประกอบของเว็บ / Shadow DOM

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

เพื่อความสมบูรณ์: ข้อกำหนด w3c

หวังว่านี่จะช่วยได้

(โปรโมทตัวเองไร้ยางอาย: ตรวจสอบ)


6
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ codepen ไม่เพียง แต่ขาดคุณสมบัติ แต่ไม่สามารถจัดการกับสิ่งต่าง ๆ เช่น css ย่อขนาดตัวแปรภาพพื้นหลังความคิดเห็นใน css เป็นต้นฉันรู้เพราะฉันทดสอบอย่างกว้างขวาง ฉันแนะนำให้ใช้ ponyfill จาก @jhildenbiddle
Andres M

ยอดเยี่ยม! ขอบคุณ!
Tackgnol

1
@Davey - ponyfill ไม่รองรับคุณสมบัติแบบกำหนดเองที่กำหนดขอบเขตไว้ดังนั้นการ--primary: #aaaประกาศจะไม่ถูกประมวลผล คำอธิบายรายละเอียดที่ระบุไว้ในปัญหานี้: ขยายการสนับสนุนด้านนอกของราก
jhildenbiddle

2
@Davey ใน IE คุณสามารถเข้าถึงค่าของคุณสมบัติที่กำหนดเองได้ แต่ไม่ต้องขึ้นต้นด้วย "-" นั่นคือวิธีการทำงานของ polyfill ของฉันโปรดดูstackoverflow.com/a/57000437/4865307
Tobias Buschor

1
FYI ฉันพบว่าสิ่งนี้เร็วกว่าทางเลือกอื่นมาก (ie11CustomProperties) - :rootข้อ จำกัด ไม่ใช่ปัญหาสำหรับฉัน { exclude: '[href*=jquery-ui],...', preserveStatic: false }สำหรับการเพิ่มประสิทธิภาพการทำงานต่อไปตรวจสอบตัวเลือกเช่น
Dunc

63

polyfill นี้ช่วยให้รองรับ Custom Properties ได้เกือบสมบูรณ์ ( ไม่ใช่เฉพาะระดับรูท ) ใน IE11:
https://github.com/nuxodin/ie11CustomProperties

มันทำงานอย่างไร

สคริปต์ใช้ประโยชน์จากข้อเท็จจริงที่ว่า IE มีการสนับสนุนคุณสมบัติที่กำหนดเองน้อยที่สุดซึ่งคุณสมบัติสามารถกำหนดและอ่านได้โดยคำนึงถึงน้ำตก
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
จากนั้นอ่านในจาวาสคริปต์:
getComputedStyle( querySelector('.myEl') )['-ie-test']

คุณสมบัติจาก README:

  • จัดการเนื้อหา 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) และไม่มีการพึ่งพา

การสาธิต:

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


1
ฉันใช้เวลาพอสมควรในการทำความเข้าใจว่าโพลีฟิลล์นี้ใช้อย่างไร README.md ไม่ชัดเจนเกี่ยวกับเรื่องนี้ วิธีแก้ไข: คุณต้องเพิ่ม<script src="yourJsPath/ie11CustomProperties.js"></script>ในส่วนหัวของไฟล์ HTML ของคุณและ IE11 จะทำงานร่วมกัน
Jpsy

1
ขอบคุณสำหรับความคิดเห็นของคุณ. ขณะนี้มีการใช้งาน
Tobias Buschor

3
สำหรับฉันโซลูชันที่บางกว่านี้เป็นแนวทางที่ถูกต้อง ponyfill ข้างต้นได้รับการจัดอันดับที่สูงกว่าเนื่องจากมีอยู่ก่อนหน้านี้ (First Commit พฤศจิกายน 2017) ในขณะที่ ie11CustomProperties มีผลครั้งแรกในเดือนกรกฎาคม 2019) ประเมินตัวเอง. อย่าทำผิดในจำนวนการโหวตที่สูงกว่าสำหรับ "คุณภาพที่ดีกว่า"
digitaldonkey

9

+1 สำหรับลิงก์ข้อมูลโค้ดปากกาในส่วนความคิดเห็นของคำถามด้านบนโดย [I has kode] สิ่งหนึ่งที่ฉันพบคือข้อมูลโค้ดต้องได้รับการแก้ไขเล็กน้อยเพื่อให้มีการประกาศฟังก์ชันที่กำหนดในรูปแบบ JSON เพื่อให้ IE11 ไม่บ่น ด้านล่างนี้คือข้อมูลโค้ดปากการุ่นแก้ไขเล็กน้อย:

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

ฉันลองใช้ 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();

0

ในการรองรับ Internet Explorer เพียงใช้สคริปต์ด้านล่างในแท็กหัว index.html และมันก็ทำงานได้อย่างมีเสน่ห์

<script>window.MSInputMethodContext && document.documentMode && document.write('<script src="https://cdn.jsdelivr.net/gh/nuxodin/ie11CustomProperties@4.1.0/ie11CustomProperties.min.js"><\x2fscript>');</script>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.