SVG 填充未在 FireFox 中应用

SVG Fill not being applied in FireFox

我似乎不明白为什么 Firefox 使用默认的 svg 填充颜色而不是 class 的填充颜色。

以下是查看 FF 检查器时的 3 个填充:

正在通过

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

它应该显示 .skip-link .icon 填充白色 (#fff) 但它实际上使用的是 #002649 的 SVG 填充;如果我将 .skip-link .icon 更改为 .skip-link svg 然后它工作正常。为什么我不能使用 class 而是明确说明元素?

我是否遗漏了一些关于 Firefox 如何填充 SVG 的明显信息? CSS 在其他浏览器中工作正常。

Robert 是正确的 <use> 并不总是应用一致。当然,当您将 SVG 用作图像时,它不知道如何应用您添加到页面的任何 CSS 规则。

但是这里还有很多其他因素可以决定元素的样式,所以举个例子可能会有帮助。

这里有一个堆栈片段来集中我们的讨论。

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>

特异性

SVG 元素本身的样式设置有多个相互冲突的规则。决定哪个规则获胜的因素与[特异性和顺序]有关。在这种情况下,SVG 元素本身将变成紫色。例如,悬停锚规则将永远不会显示,因为它不如 .skip-link .icon

具体

继承

某些属性允许从其父项继承,但仅在未自行指定时才允许。任何规范都将覆盖继承的值。如果问题是,我的 <svg> 元素具有某种样式,为什么不将它平等地应用于所有子元素,答案很简单。子元素指定自己的值并覆盖继承的值是完全没问题的。

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

使用 & Xlink

棘手的部分变成了涉及使用时会发生什么。在这种情况下,很难追踪实际应用的样式。使用将创建由 xlink 属性标识的元素的内联表示,但您不能直接访问该元素。因此,在开发人员工具中选择 use 只会显示应用于元素父元素的样式。元素本身可能会覆盖继承的属性,我们无法在开发面板中观察到它。

这里举例来说,应用使用的样式是继承自parent的。在开发者工具中,似乎获胜规则是紫色的,但这只是因为它没有考虑被拉入的元素。这是一个 soft 值,可以如果元素指定任何值,则被覆盖。

但是内联文本的全套选择器实际上看起来像这样:

具体情况

我将来建议的一件事是提供可运行的代码,其他人可以使用它来轻松重现问题,因为它可以节省大量额外的调试时间。但是,我怀疑您的具体情况是这样的:

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>

如果该行为是版本 56 之前的 Firefox 独有的,那是因为 #menu-bag 引用了 <symbol> 元素。

规格说重新使用 <symbol> should be implemented as if it were replaced by a nested <svg>。 Firefox 曾经在他们的影子 DOM 中按字面意思对待这个问题。阴影 DOM 在您的 DOM 检查器中不可见,但它受 CSS select 或

的约束

也就是说这段代码:

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

WA 是这样实现的:

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

svg.icon 匹配您的 .skip-link .icon 规则(正如 Kyle Mitt 指出的那样,该规则将始终优先于您的 a:hover svg 规则)。该值也由 <use> 元素继承。

然而,shadow-DOM <svg> 没有获得继承的值,因为它是直接使用 svg 规则设置样式的。当您将 selector 更改为 .skip-link svg 时,或者当您触发 a:hover svg 规则时,隐藏的内部元素将直接应用样式,因为该 SVG 也是 [= 的后代89=].

正如 Robert Longson 在评论中指出的那样,这不是 应该 工作的方式。这是 Firefox 将 <use> 元素实现为完全克隆的 DOM 树的方式的副作用,它恰好对你的 DOM 检查器隐藏了。

这是您的原始问题的 "working" 示例。也就是说,在 Chrome、Safari、Opera、Firefox 56+ 或 IE 上你会看到一个绿色圆圈,当你悬停它时它不会改变,但在版本 56 之前的 Firefox 上你会看到一个蓝色圆圈在 hover/focus.

时变为红色

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>

那么如果你需要支持旧版本的 Firefox 怎么办?你有两个选择,其中之一你已经通过反复试验找到了:

  1. 避免使用 svg 标签设置默认样式 select 或者,依赖 <use> 元素的正常样式继承。

  2. 使用 select 或故意 select 影子-<svg> 来取消默认值,同时确保它们对其他人有预期的效果浏览器。

一种选择是使用如下规则,这将保持原始规则对其他浏览器的特异性:

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

use>svg selector 永远不会匹配任何 除了 Firefox bug,所以可以安全使用没有副作用。 (最初,我只是建议将 svg 添加到 selector 的末尾,但在某些情况下这可能会出现问题。)

在 body 或 html 标签上设置默认的 svg 填充颜色,它将作为默认值继承,但您可以使用 class.

轻松覆盖它
body {
    fill: black;
}
.green {
    fill: green;
}
.red {
    fill: red;
}

现在只需在任何地方使用 class 颜色即可更改填充颜色。将颜色 class 添加到 svg,或添加到 span 或其他包装 svg 的元素。也适用于 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>

基于@AmeliaBR 提供的答案的更通用的选项是简单地按照以下方式做一些事情:

svg use svg { 
    fill: inherit;
}

这将使阴影元素继承填充颜色。

我的情况不完全一样,但我还是分享一下。 我使用 svg 作为背景图片,就像下面的例子(谷歌搜索,不记得在哪里)。在 Firefox 中 "fill" 颜色有问题。

  • 作为填充值,我不得不在RGB模式下编写它并正常工作(fill:rgb(237, 237, 237);)。
  • 如果我用十六进制写入(填充:#ededed;),它不会呈现。
  • 如果我写例如"fill: blue;"它也会正确显示。

    .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;
    

    }