web-dev-qa-db-fra.com

Le remplissage SVG n'est pas appliqué dans FireFox

Je n'arrive pas à comprendre pourquoi Firefox utilise la couleur de remplissage par défaut svg au lieu du remplissage de la classe.

Voici les 3 remplissages lors de l'affichage de l'inspecteur FF: 

CSS

SVG est inséré via

<svg class="icon">
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag"></use>
</svg>

Il devrait afficher le remplissage .skip-link .icon de blanc (#fff), mais il utilise en réalité le remplissage SVG de # 002649; Si je change .skip-link .icon en .skip-link svg, alors cela fonctionne très bien. Pourquoi ne puis-je pas utiliser une classe et plutôt déclarer explicitement l'élément?

Me manque-t-il quelque chose d'évident sur la façon dont Firefox remplit un SVG? Ce CSS fonctionne très bien dans les autres navigateurs.

12
Gil

Si le comportement était unique à Firefox avant la version 56, c'était parce que #menu-bag faisait référence à un élément <symbol>

Les spécifications indiquent qu'un <symbol>réutilisé doit être implémenté comme s'il était remplacé par un <svg> imbriqué. Firefox avait l'habitude de traiter cela littéralement dans leur DOM ombre. Le DOM fantôme n'est pas visible dans votre inspecteur DOM, mais il est soumis aux sélecteurs CSS.

Ce qui signifie que ce code:

<a href="#" class="skip-link">
    <svg class="icon">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag"></use>
    </svg>
</a>

Les WA implémentés comme ceci:

<a href="#" class="skip-link">
    <svg class="icon">  
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag">
          <!--Start of shadow DOM boundary-->
          <svg><!-- replacement for <symbol> -->
             <!-- graphics content -->
          </svg>
          <!--End of shadow DOM boundary-->
        </use>
    </svg>
</a>

Le svg.icon correspond à votre règle .skip-link .icon (et comme le souligne Kyle Mitt, cette règle aura toujours priorité sur votre règle a:hover svg). Cette valeur est également héritée par l'élément <use>.

Cependant, shadow-DOM <svg> ne récupère pas la valeur héritée, car il est directement stylé avec la règle svg. Lorsque vous définissez votre sélecteur sur .skip-link svg ou lorsque vous déclenchez la règle a:hover svg, l'élément interne masqué se voit appliquer directement le style, car ce fichier SVG est également un descendant du lien.

Comme Robert Longson l'a noté dans les commentaires, ce n'est pas comme ça que (supposé} _ fonctionne. C'est un effet secondaire de la façon dont Firefox a implémenté les éléments <use> en tant qu'arbres DOM clonés complets, qui venaient juste d'être cachés de votre inspecteur DOM.

Voici un exemple "fonctionnel" de votre problème initial. C’est-à-dire que sur Chrome, Safari, Opera, Firefox 56+ ou IE, vous verrez un cercle vert qui n’est pas modifié lorsque vous le survolez, mais sur Firefox avant la version 56, vous verrez apparaître un cercle vert. cercle bleu qui devient rouge en survol/mise au point.

svg {
    fill: navy;
}
a:hover svg, a:focus svg {
    fill: red;
}
.skip-link .icon {
    fill: green;
}
.icon {
    height: 50;
    width: 50;
}
 <a href="#" class="skip-link">
        <svg class="icon">
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag" />
        </svg>
</a>
<svg height="0" width="0">
    <symbol id="menu-bag" viewBox="-10 -10 20 20">
        <circle r="10" />
    </symbol>
</svg>

Alors que faire si vous avez besoin de supporter les anciennes versions de Firefox? Vous avez deux options, dont l'une que vous avez déjà déterminée par essais et erreurs:

  1. Évitez de définir des styles par défaut à l'aide du sélecteur de balises svg et utilisez l'héritage de style normal de l'élément <use>

  2. Utilisez des sélecteurs qui sélectionnent intentionnellement shadow -<svg> pour annuler les valeurs par défaut, tout en veillant à ce qu'ils aient l'effet escompté sur les autres navigateurs.

Une option serait d'utiliser une règle comme celle-ci, qui conserverait la spécificité de votre règle d'origine pour les autres navigateurs:

.skip-link .icon, .skip-link .icon use>svg {
    fill: green;
}

Le sélecteur use>svg ne trouvera jamais rien sauf avec le bogue Firefox , il est donc prudent de l'utiliser sans effets secondaires. (À l'origine, je suggérais simplement d'ajouter svg à la fin du sélecteur, mais cela pourrait poser problème dans certaines situations.)

36
AmeliaBR

Une option plus universelle basée sur la réponse fournie par @AmeliaBR consiste simplement à faire quelque chose dans le sens suivant:

svg use svg { 
    fill: inherit;
}

ce qui fera que l'élément ombre héritera de la couleur de remplissage.

3
Derek Story

Robert a raison de dire que <use> n'est pas toujours appliqué de manière uniforme. Bien sûr, lorsque vous utilisez un fichier SVG en tant qu’image, il ne sait pas comment appliquer les règles CSS que vous avez ajoutées à votre page.

Mais il y a beaucoup d'autres choses ici aussi qui pourraient décider du style de l'élément, un exemple pourrait donc être utile.

Voici un extrait de pile pour centrer notre discussion.

svg {
  fill: blue;
}
a:hover svg {
  fill: red;
}
.skip-link .icon {
  fill: purple;
}

.green {
  fill: green;
}
<a href="#" class="skip-link">
  <svg xmlns="http://www.w3.org/2000/svg"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       class="icon" >

    <def>
      <text id="text" >use xlink</text>
      <text id="over" class="green">use xlink override</text>
    </def>
    
    <text x="5" y="15" >Plain</text>
    <use  x="5" y="30" xlink:href="#text" />

    <use  x="5" y="50" xlink:href="#over" />
    <text x="5" y="65" class="green" >class="green"</text>
    <text x="5" y="80" fill="orange" >fill="orange"</text>

  </svg>
</a>

Spécificité

L'élément SVG lui-même est stylé avec plusieurs règles contradictoires. Ce qui détermine quelle règle gagne est lié à [spécificité et ordre]. Dans ce cas, l'élément SVG lui-même deviendra violet. La règle d'ancrage survolé, par exemple, n'apparaîtra jamais car elle est moins spécifique que .skip-link .icon

SVG

Héritage

Certaines propriétés permettent l'héritage de leurs parents, mais uniquement lorsqu'elles ne sont pas spécifiées elles-mêmes. Toutes les spécifications remplaceront la valeur héritée. Si la question est, mon élément <svg> a un certain style, pourquoi ne l'applique-t-il pas de la même manière à tous les éléments enfants, la réponse est simple. Il est parfaitement correct que les éléments enfants spécifient leur propre valeur et remplacent celle héritée.

<text x="5" y="65" style="fill:green;" >class="green"</text>
<text x="5" y="80" fill="orange" >fill="orange"</text>

Utiliser & Xlink

La partie délicate devient ce qui se passe quand l'utilisation est impliquée. Dans ce cas, il peut être difficile de tracer les styles appliqués. Utiliser créera une représentation en ligne de l'élément identifié par l'attribut xlink, mais vous ne pourrez pas accéder directement à cet élément. Par conséquent, si vous sélectionnez use dans les outils de développement, seuls les styles appliqués au parent de l'élément seront révélés. L'élément lui-même peut remplacer les propriétés héritées et nous n'aurions aucun moyen de l'observer dans le panneau de développement.

Ici, par exemple, le style appliqué à utiliser est hérité du parent. Dans les outils de développement, il apparaît que la règle gagnante est violette, mais uniquement parce qu’elle n’a pas pris en compte l’élément inséré. Il s’agit d’une valeur soft qui peut être remplacée si l’élément spécifie n'importe quelle valeur.

use

Mais le jeu complet de sélecteurs pour le texte incorporé ressemblerait en réalité à ceci:

text

Situation spécifique

Une chose que je suggérerais à l’avenir est en fournissant du code exécutable que d’autres personnes peuvent utiliser pour reproduire facilement le problème, car cela permet d’économiser beaucoup de temps de débogage. Cependant, voici ce que je soupçonne que se passe avec votre situation exacte:

svg {
  fill: #002649;
}
a:hover svg {
  fill: #8A8B8C;
}
.skip-link .icon {
  fill: #FFF;
}
<a href="#" class="skip-link">
  <svg xmlns="http://www.w3.org/2000/svg"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       class="icon" >

    <def>
      <svg xmlns="http://www.w3.org/2000/svg" id="menu-bag">
        <rect height="100" width="100" />
      </svg>
    </def>

    <use xlink:href="#menu-bag" />

  </svg>
</a>

2
KyleMit

Définissez votre couleur de remplissage svg par défaut sur la balise body ou html et elle sera héritée par défaut, mais vous pouvez facilement la remplacer en utilisant simplement une classe.

body {
    fill: black;
}
.green {
    fill: green;
}
.red {
    fill: red;
}

Utilisez maintenant la classe de couleur n’importe où pour modifier la couleur de remplissage. Ajoutez la classe de couleur au svg, à une étendue ou à un autre élément enveloppant le svg. Fonctionne aussi dans Firefox. 

<a href="#" class="skip-link green">
    <svg>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag" />
    </svg>
</a>
<svg height="0" width="0">
    <symbol id="menu-bag" viewBox="-10 -10 20 20">
        <circle r="10" />
    </symbol>
</svg>
1
user3735371

Mon cas n'est pas exactement le même, mais je le partage quand même. J'utilise svg en tant qu'image d'arrière-plan, comme dans l'exemple ci-dessous (googlé pour cela, ne vous souvenez plus où). Et dans Firefox avait des problèmes avec la couleur de "remplissage".

  • En tant que valeur de remplissage, je devais l'écrire en mode RVB et fonctionnait correctement (remplissage: rgb (237, 237, 237);).
  • Si j’écrivais dans HEX (fill: #ededed;), cela ne rendrait pas.
  • Si j'ai écrit par exemple "fill: blue;" il montrerait également correctement.

    .a-class {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 10' preserveAspectRatio='none' height='130' style='background:var(--main-lt-green); fill:rgb(237, 237, 237);'><polygon points='100 0 100 10 0 10'></polygon></svg>");
    background-repeat: no-repeat;
    background-size: 100% 100px;
    background-position-y: top;
    margin-top: -100px;
    padding-top: 100px;
    

    }

0