IE11 - Gibt es eine Polyfüllung / ein Skript für CSS-Variablen?

88

Ich entwickle eine Webseite in einer gemischten Webbrowser-Umgebung (Chrome / IE11). IE11 unterstützt keine CSS-Variablen. Gibt es eine Polyfüllung oder ein Skript, mit dem ich CSS-Variablen in IE11 verwenden kann?

R. StackUser
quelle
Welche Art von CSS-Variablen?
Bhansa
@ R.StackUser Markieren Sie eine der folgenden Antworten als die richtige. Prost.
AndrewL64
Schauen Sie sich diese Custom-Properties-Polyfill an: github.com/nuxodin/ie11CustomProperties
Tobias Buschor

Antworten:

108

Ja, solange Sie benutzerdefinierte Eigenschaften auf Stammebene (IE9 +) verarbeiten.

Aus der README:

Eigenschaften

  • Clientseitige Umwandlung von benutzerdefinierten CSS-Eigenschaften in statische Werte
  • Live-Updates von Laufzeitwerten in modernen und älteren Browsern
  • Wandelt <link>, <style>und @importCSS
  • Wandelt relative url()Pfade in absolute URLs um
  • Unterstützt verkettete und verschachtelte var()Funktionen
  • Unterstützt var()Funktionsrückfallwerte
  • Unterstützt Webkomponenten / Shadow DOM CSS
  • Der Überwachungsmodus wird automatisch aktualisiert <link>und <style>geändert
  • UMD- und ES6-Modul verfügbar
  • TypeScript-Definitionen enthalten
  • Leicht (6k min + gzip) und abhängig

Einschränkungen

  • Die Unterstützung von benutzerdefinierten Eigenschaften ist auf :rootund :hostDeklarationen beschränkt
  • Die Verwendung von var () ist auf Eigenschaftswerte beschränkt (gemäß W3C-Spezifikation ).

Hier einige Beispiele, wie die Bibliothek umgehen kann:

Benutzerdefinierte Eigenschaften auf Stammebene

:root {
    --a: red;
}

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

Verkettete benutzerdefinierte Eigenschaften

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

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

Verschachtelte benutzerdefinierte Eigenschaften

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

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

Fallback-Werte

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

Wandelt <link>, <style>und @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>

Transformiert Webkomponenten / Schatten-DOM

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

Der Vollständigkeit halber: w3c specs

Hoffe das hilft.

(Schamlose Eigenwerbung: Check)

jhildenbiddle
quelle
6
Dies sollte die akzeptierte Antwort sein. Dem Codepen fehlen nicht nur Funktionen, sondern er kann auch Dinge wie minimiertes CSS, Hintergrundbildvariablen, Kommentare im CSS usw. nicht verarbeiten. Ich weiß es, weil ich es ausgiebig getestet habe. Ich empfehle die Ponyfüllung von @jhildenbiddle
Andres M
Ausgezeichnet! Danke dir!
Tackgnol
Nett! Angenommen, ich setze : :root { --primary: #fff } body.certain-page { --primary: #aaa }. Wie könnte ich mit Ihrem Plugin damit umgehen?
Davey
1
@ Davey - Die Pony-Füllung unterstützt keine benutzerdefinierten Eigenschaften mit Gültigkeitsbereich, daher wird die --primary: #aaaDeklaration nicht verarbeitet. Eine ausführlichere Erklärung finden Sie in dieser Ausgabe: Erweitern der Unterstützung außerhalb von: root .
jhildenbiddle
2
@ Davey im IE können Sie auf den Wert benutzerdefinierter Eigenschaften zugreifen, jedoch nicht beginnend mit "-". So funktioniert meine Polyfüllung
Tobias Buschor
57

Diese Polyfüllung ermöglicht eine fast vollständige Unterstützung für benutzerdefinierte Eigenschaften ( nicht nur auf Stammebene ) in IE11:
https://github.com/nuxodin/ie11CustomProperties

Wie es funktioniert

Das Skript nutzt die Tatsache, dass der IE nur minimale Unterstützung für benutzerdefinierte Eigenschaften bietet, bei denen Eigenschaften unter Berücksichtigung der Kaskade definiert und ausgelesen werden können.
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
dann lesen Sie es in Javascript:
getComputedStyle( querySelector('.myEl') )['-ie-test']

Features aus der README:

  • behandelt dynamisch hinzugefügten HTML-Inhalt
  • Griffe dynamisch hinzugefügt <style>, <link>-Elemente
  • Verkettung --bar:var(--foo)
  • Zurückfallen var(--color, blue)
  • : focus ,: target ,: hover
  • js-Integration:
    • style.setProperty('--x','y')
    • style.getPropertyValue('--x')
    • getComputedStyle(el).getPropertyValue('--inherited')
  • Inline-Stile: <div ie-style="--color:blue"...
  • Kaskade funktioniert
  • Vererbung funktioniert
  • unter 3k (min + gzip) und abhängigkeitsfrei

Demo:

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

Tobias Buschor
quelle
1
Ich habe einige Zeit gebraucht, um zu verstehen, wie diese Polyfüllung verwendet wird. Die README.md ist nicht sehr klar darüber. Lösung: Sie müssen lediglich <script src="yourJsPath/ie11CustomProperties.js"></script>den Kopfbereich Ihrer HTML-Datei hinzufügen , und IE11 stimmt überein.
Jpsy
1
Danke für deine Rückmeldung. Es gibt jetzt eine Usesage-Sektion
Tobias Buschor
3
Für mich ist diese viel schlankere Lösung der richtige Ansatz. Die oben genannte Ponyfüllung ist aufgrund früherer Existenz nur höher bewertet (First Commit Nov 2017), während ie11CustomProperties erstmals im Juli 2019 festgeschrieben wurde. Bewerten Sie sich. FEHLEN SIE NICHT DIE HÖHERE ANZAHL DER STIMMEN FÜR "BESSERE QUALITÄT".
Digitaldonkey
9

+1 für den Code-Pen-Snippet-Link im obigen Kommentarbereich von [I has kode]. Eine Sache, die ich jedoch gefunden habe, ist, dass das Snippet leicht modifiziert werden muss, damit die Funktionsdeklarationen im JSON-Format definiert sind, damit IE11 sich nicht beschwert. Unten finden Sie die leicht modifizierte Version des Codestift-Snippets:

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

Ich habe diese Version von Polyfill ausprobiert, aber es kam zu Fehlern, wenn eine Zeile in CSS mehrere Variablen (FI-Schriftart und Farbe) enthielt. Ein Kollege von mir hat mir geholfen. Siehe Zeile 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();
Mürrischer alter Bastard
quelle
0

Um den Internet Explorer zu unterstützen, verwenden Sie einfach das folgende Skript im index.html-Head-Tag und es funktioniert wie ein Zauber.

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