SVG 将渐变修改为与 "use" 重用的元素

SVG modifying gradient to an element that is reused with "use"

我正在使用一个简单的 SVG 三角形路径,它是 fill 通过 CSS 使用对 SVG 渐变 的引用编辑的].

SVG:

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <linearGradient id="gradient">
        <stop offset="0%" />
        <stop offset="100%" />
      </linearGradient>
    <polygon id="triangle" points="0,0 100,0 0,66" />     
</svg>

CSS:

#triangle {
  fill: url(#gradient);
}

在渐变中使用的颜色有更多自由度,并且 从标记中获取颜色 我选择使用 CSS custom properties (aka CSS Variables)

CSS:

#gradient stop:first-child {
    stop-color: var(--color-stop);
}
#gradient stop {
    stop-color: var(--color-stop2);
}

到目前为止还不错,问题是我想重新使用那个三角形并给它另一种颜色。 覆盖 CSS 变量无效! https://codepen.io/Type-Style/pen/gNYpjL

// nothing in js this time
svg {width: 250px; height:200px;}
:root {
  --color-stop: orange;
  --color-stop2: red;
}
.second { /* has no effect */
  --color-stop: lime;
   --color-stop2: green; 
}

#gradient stop:first-child {
 stop-color: var(--color-stop);
}
#gradient stop {
 stop-color: var(--color-stop2);
}

#triangle {
  fill: url(#gradient);
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <linearGradient id="gradient">
        <stop offset="0%" />
        <stop offset="100%" />
      </linearGradient>
    <polygon id="triangle" points="0,0 100,0 0,66" />   
</svg>
<svg class="second" viewBox="0 0 100 100">
 <use class="use-triangle" href="#triangle" />
</svg>

预期结果:

我希望用不同的方式着色第二个三角形。


结果:

但是好像一旦用了渐变,就没办法modifying/overwriting了。 感觉渐变只取直接分配给它的值,使用后无法更改。 这可能是由于引用 ID 的填充用法的性质,但我不确定


我尝试过的/功劳:

我检查了 SVG gradient using CSS,这是我从中获取和修改示例的地方。 (感谢@Maciej-Kwas)

此外,我知道您可以 inherit fill and use currentColor 为 "used" 的元素提供更多颜色。但到目前为止,我还无法让它与渐变一起工作。


不满意的解决方法:

因为我的目标是将颜色保留在标记之外,所以我可以将 svg 移动到 css 内联作为数据 Uri,就像这样:

fill: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><linearGradient id='grad'><stop offset='0%' stop-color='%23ff00cc'/><stop offset='100%' stop-color='%23333399'/></linearGradient></svg>#grad")

有关这篇文章的重要功劳:https://fvsch.com/svg-gradient-fill/

但是因为这只适用于 Firefox,而且看起来很老套。


结束语:

请问有没有其他解决办法。并且想首先详细了解为什么它不能像我预期的那样工作。

我不确定您是否正在寻找通用解决方案,但对于这种特殊情况,您可以使用纯 CSS 来达到相同的效果。

下面的技巧很有效,因为渐变方向是水平的:

:root {
  --c1: orange;
  --c2: red;
}

.second {
  --c1: lime;
  --c2: green;
}

.triangle {
  width: 200px;
  height: 132px;
  display: inline-block;
  overflow: hidden;
  position: relative;
}

.triangle:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(to right, var(--c1), var(--c2));
  transform: skewY(-33.42deg); /* arctan(132/200)*/
  transform-origin: left;
}
<div class="triangle">

</div>

<div class="triangle second">

</div>

您还可以考虑 clip-path,这样可以更轻松地定义任何类型的渐变,但您需要注意浏览器支持。您可能还会注意到多边形的语法与 SVG 中的语法几乎相似,因此您也可以考虑任何一种形状。

:root {
  --c1: orange;
  --c2: red;
}

.second {
  --c1: lime;
  --c2: green;
}

.triangle {
  width: 200px;
  height: 132px;
  display: inline-block;
  background: linear-gradient(65deg, var(--c1), var(--c2));
  -webkit-clip-path:polygon(0 0,100% 0,0 100%);
  clip-path:polygon(0 0,100% 0,0 100%);
}
<div class="triangle">

</div>

<div class="triangle second">

</div>

两个观察结果:

  1. 您需要定义 2 个渐变并选择带有变量的渐变:fill: var(--grd);

  2. 您没有填写需要重复使用的<polygon>。您填写 <use> 元素。

希望对您有所帮助。

svg {width: 250px; height:200px;border:1px solid}
:root {
  --grd: url(#gradient);
}
.second{--grd: url(#gradient2);}

use {
  fill: var(--grd);
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> 
 <defs>
    <linearGradient id="gradient">
        <stop offset="0%" stop-color="orange"/>
        <stop offset="100%" stop-color="red" />
      </linearGradient>
   <linearGradient id="gradient2">
        <stop offset="0%" stop-color="lime"/>
        <stop offset="100%" stop-color="green" />
      </linearGradient>
    <polygon id="triangle" points="0,0 100,0 0,66" />  
 </defs>
 
 <use class="use-triangle" xlink:href="#triangle" />
</svg>
<svg class="second" viewBox="0 0 100 100">
 <use class="use-triangle" xlink:href="#triangle" />
</svg>