IE11 - existe-t-il un polyfill / script pour les variables CSS?

93

Je développe une page Web dans un environnement de navigateur Web mixte (Chrome / IE11). IE11 ne prend pas en charge les variables CSS, existe-t-il un polyfill ou un script qui me permettrait d'utiliser des variables CSS dans IE11?

R. StackUser
la source
Quel genre de variables css?
bhansa le
@ R.StackUser Marquez l'une des réponses ci-dessous comme la bonne. À votre santé.
AndrewL64
Jetez un œil à ce Custom-Properties-Polyfill: github.com/nuxodin/ie11CustomProperties
Tobias Buschor

Réponses:

114

Oui, tant que vous traitez les propriétés personnalisées au niveau racine (IE9 +).

Depuis le README:

traits

  • Transformation côté client des propriétés personnalisées CSS en valeurs statiques
  • Mises à jour en direct des valeurs d'exécution dans les navigateurs modernes et hérités
  • Transforms <link>, <style>et @importCSS
  • Transforme les url()chemins relatifs en URL absolues
  • Prend en charge les var()fonctions chaînées et imbriquées
  • Prend en charge var()les valeurs de secours des fonctions
  • Prend en charge les composants Web / shadow DOM CSS
  • Mise à jour automatique du mode montre <link>et <style>modifications
  • Module UMD et ES6 disponible
  • Définitions TypeScript incluses
  • Léger (6k min + gzip) et sans dépendance

Limites

  • La prise en charge des propriétés personnalisées est limitée aux déclarations :rootet:host
  • L'utilisation de var () est limitée aux valeurs de propriété (selon la spécification W3C )

Voici quelques exemples de ce que la bibliothèque peut gérer:

Propriétés personnalisées au niveau racine

:root {
    --a: red;
}

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

Propriétés personnalisées chaînées

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

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

Propriétés personnalisées imbriquées

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

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

Valeurs de repli

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

Transforms <link>, <style>et @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>

Transforme les composants 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>

Par souci d'exhaustivité: les spécifications W3C

J'espère que cela t'aides.

(Auto-promotion sans vergogne: vérifier)

jhildenbiddle
la source
6
Cela devrait être la réponse acceptée. Non seulement le codepen manque de fonctionnalités, mais il ne peut pas gérer des choses comme des css minimisés, des variables d'image d'arrière-plan, des commentaires dans le css, etc. Je le sais parce que je l'ai testé de manière approfondie. Je recommande d'utiliser le ponyfill de @jhildenbiddle
Andres M
Excellent! Merci!
Tackgnol
1
@Davey - Le ponyfill ne prend pas en charge les propriétés personnalisées étendues, donc la --primary: #aaadéclaration ne sera pas traitée. Une explication plus détaillée est fournie dans ce numéro: Extension du support en dehors de: root .
jhildenbiddle
2
@Davey dans IE vous pouvez accéder à la valeur des propriétés personnalisées mais pas en commençant par "-". C'est la façon dont mon polyfill fonctionne, voir stackoverflow.com/a/57000437/4865307
Tobias Buschor
1
Pour info, j'ai trouvé cela beaucoup plus rapide que l'alternative (ie11CustomProperties) - la :rootlimitation n'est pas un problème pour moi. Pour d'autres gains de performances, consultez les options, par exemple { exclude: '[href*=jquery-ui],...', preserveStatic: false }.
Dunc
63

Ce polyfill permet une prise en charge presque complète des propriétés personnalisées ( pas seulement au niveau racine ) dans IE11:
https://github.com/nuxodin/ie11CustomProperties

Comment ça fonctionne

Le script utilise le fait que IE a une prise en charge minimale des propriétés personnalisées où les propriétés peuvent être définies et lues avec la cascade à l'esprit.
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
puis lisez-le en javascript:
getComputedStyle( querySelector('.myEl') )['-ie-test']

Caractéristiques du README:

  • gère le contenu HTML ajouté dynamique
  • gère les ajouts dynamiques <style>, <link>-éléments
  • enchaînement --bar:var(--foo)
  • se retirer var(--color, blue)
  • : focus,: cible,: survol
  • js-intégration:
    • style.setProperty('--x','y')
    • style.getPropertyValue('--x')
    • getComputedStyle(el).getPropertyValue('--inherited')
  • Styles en ligne: <div ie-style="--color:blue"...
  • travaux en cascade
  • l'héritage fonctionne
  • sous 3k (min + gzip) et sans dépendance

Démo:

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

Tobias Buschor
la source
1
Il m'a fallu un certain temps pour comprendre comment ce polyfill est utilisé. Le README.md n'est pas très clair à ce sujet. Solution: il vous suffit d'ajouter <script src="yourJsPath/ie11CustomProperties.js"></script>à la section head de votre fichier HTML et IE11 sera d'accord.
Jpsy
1
Merci pour votre avis. Il y a maintenant une section ussage
Tobias Buschor
3
Pour moi, cette solution beaucoup plus mince est la bonne approche. Le ponyfill ci-dessus n'est mieux noté en raison de son existence antérieure (premier commit nov 2017), alors que ie11CustomProperties s'est engagé pour la première fois en juillet 2019). Évaluez-vous. NE MANQUEZ PAS LE PLUS GRAND NOMBRE DE VOTES POUR UNE «MEILLEURE QUALITÉ».
digitaldonkey
9

+1 pour le lien d'extrait de code-stylo dans la section commentaire de question ci-dessus par [I has kode]. Une chose que j'ai trouvée cependant est que l'extrait de code doit être légèrement modifié pour que les déclarations de fonction soient définies au format JSON pour que IE11 ne se plaigne pas. Voici la version légèrement modifiée de l'extrait de code du stylet:

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
la source
3

J'ai essayé cette version de Polyfill mais je me suis retrouvé avec des erreurs lorsqu'une ligne de CSS avait plusieurs variables (police et couleur FI). Un de mes collègues m'a aidé. Lisez la ligne 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();
Vieux bâtard grincheux
la source
0

Pour prendre en charge Internet Explorer, utilisez simplement le script ci-dessous dans la balise head index.html et cela fonctionne comme un charme.

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