IE11 - apakah ada polyfill / script untuk variabel CSS?

93

Saya mengembangkan halaman web dalam lingkungan browser web campuran (Chrome / IE11). IE11 tidak mendukung variabel CSS, apakah ada polyfill atau skrip yang memungkinkan saya menggunakan variabel CSS di IE11?

R. StackUser
sumber
Variabel css seperti apa?
bhansa
@ R.StackUser Lakukan tandai salah satu jawaban di bawah ini sebagai jawaban yang benar. Bersulang.
AndrewL64
Lihat Custom-Properties-Polyfill ini: github.com/nuxodin/ie11CustomProperties
Tobias Buschor

Jawaban:

114

Ya, selama Anda memproses properti kustom tingkat root (IE9 +).

Dari README:

fitur

  • Transformasi sisi klien dari properti khusus CSS menjadi nilai statis
  • Pembaruan langsung dari nilai waktu proses di browser modern dan lama
  • Mentransformasi <link>, <style>dan @importCSS
  • Mengubah url()jalur relatif menjadi URL absolut
  • Mendukung var()fungsi berantai dan bersarang
  • Mendukung var()nilai fallback fungsi
  • Mendukung komponen web / shadow DOM CSS
  • Pembaruan otomatis mode jam tangan <link>dan <style>perubahan
  • Modul UMD dan ES6 tersedia
  • Definisi TypeScript disertakan
  • Ringan (6k mnt + gzip) dan bebas ketergantungan

Batasan

  • Dukungan properti kustom terbatas pada :rootdan :hostdeklarasi
  • Penggunaan var () terbatas pada nilai properti (sesuai spesifikasi W3C )

Berikut adalah beberapa contoh yang dapat ditangani oleh perpustakaan:

Properti kustom tingkat root

:root {
    --a: red;
}

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

Properti kustom yang dirantai

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

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

Properti khusus bersarang

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

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

Nilai fallback

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

Mentransformasi <link>, <style>dan @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>

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

Demi kelengkapan: spesifikasi w3c

Semoga ini membantu.

(Promosi diri yang tidak tahu malu: Periksa)

jhildenbiddle
sumber
6
Ini harus menjadi jawaban yang diterima. Codepen tidak hanya kekurangan fitur, tetapi tidak dapat menangani hal-hal seperti css yang diminimalkan, variabel gambar latar belakang, komentar di css, dll. Saya tahu karena saya mengujinya secara ekstensif. Saya merekomendasikan penggunaan ponyfill dari @jhildenbiddle
Andres M
Luar biasa! Terima kasih!
Tackgnol
1
@Davey - Ponyfill tidak mendukung properti khusus terbatas, sehingga --primary: #aaadeklarasi tidak akan diproses. Penjelasan lebih rinci diberikan dalam edisi ini: Memperluas dukungan di luar: root .
jhildenbiddle
2
@Davey di IE Anda dapat mengakses nilai properti khusus tetapi tidak dimulai dengan "-". Begitulah cara kerja polyfill saya, lihat stackoverflow.com/a/57000437/4865307
Tobias Buschor
1
FYI, saya menemukan ini jauh lebih cepat daripada alternatif (ie11CustomProperties) - :rootbatasan bukan masalah bagi saya. Untuk peningkatan kinerja lebih lanjut, periksa opsinya, mis { exclude: '[href*=jquery-ui],...', preserveStatic: false }.
Dunc
63

Polyfill ini memungkinkan dukungan yang hampir lengkap untuk Properti Khusus ( tidak hanya tingkat akar ) di IE11:
https://github.com/nuxodin/ie11CustomProperties

Bagaimana itu bekerja

Skrip memanfaatkan fakta bahwa IE memiliki dukungan properti kustom minimal di mana properti dapat didefinisikan dan dibaca dengan mempertimbangkan kaskade.
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
lalu baca di javascript:
getComputedStyle( querySelector('.myEl') )['-ie-test']

Fitur dari README:

  • menangani konten html yang ditambahkan secara dinamis
  • menangani penambahan dinamis <style>, <link>-elemen
  • rantai --bar:var(--foo)
  • fallback var(--color, blue)
  • : fokus,: target,: hover
  • js-integrasi:
    • style.setProperty('--x','y')
    • style.getPropertyValue('--x')
    • getComputedStyle(el).getPropertyValue('--inherited')
  • Gaya sebaris: <div ie-style="--color:blue"...
  • cascade bekerja
  • warisan bekerja
  • di bawah 3k (min + gzip) dan bebas ketergantungan

Demo:

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

Tobias Buschor
sumber
1
Butuh beberapa waktu bagi saya untuk memahami bagaimana polyfill ini digunakan. README.md tidak begitu jelas tentangnya. Solusi: Anda hanya perlu menambahkan <script src="yourJsPath/ie11CustomProperties.js"></script>ke bagian head dari file HTML Anda dan IE11 akan setuju.
Jpsy
1
Terima kasih atas tanggapan Anda. Sekarang ada bagian penggunaan
Tobias Buschor
3
Bagi saya, solusi yang jauh lebih ramping ini adalah pendekatan yang tepat. Ponyfill di atas hanya berperingkat lebih tinggi karena keberadaan sebelumnya (Komitmen pertama Nov 2017), sementara ie11CustomProperties pertama kali dilakukan pada Juli 2019). Evaluasi diri Anda. JANGAN SALAHKAN JUMLAH SUARA YANG LEBIH TINGGI UNTUK "KUALITAS YANG LEBIH BAIK".
digitaldonkey
9

1 untuk tautan cuplikan kode-pena di bagian komentar pertanyaan di atas oleh [Saya punya kode]. Satu hal yang saya temukan adalah potongannya perlu sedikit dimodifikasi agar deklarasi fungsi didefinisikan dalam format JSON agar IE11 tidak mengeluh. Di bawah ini adalah versi potongan pena kode yang sedikit dimodifikasi:

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();
ajawad987
sumber
3

Saya mencoba versi Polyfill ini tetapi berakhir dengan kesalahan ketika satu baris di CSS memiliki banyak variabel (font dan warna FI). Seorang rekan saya membantu saya. Lihat baris 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();
Bajingan Tua Pemarah
sumber
0

Untuk mendukung Internet Explorer, Cukup gunakan skrip di bawah ini di tag head index.html dan itu bekerja seperti pesona.

<script>window.MSInputMethodContext && document.documentMode && document.write('<script src="https://cdn.jsdelivr.net/gh/nuxodin/[email protected]/ie11CustomProperties.min.js"><\x2fscript>');</script>
Rohinibabu
sumber