I am using a simple SVG triangle shaped path that is filled via CSS using a reference to an SVG Gradient.
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);
}
To have a little bit more freedom with the colors used in the gradient and to get the colors out of the markup I opted to use CSS custom properties (aka CSS Variables)
CSS:
#gradient stop:first-child {
stop-color: var(--color-stop);
}
#gradient stop {
stop-color: var(--color-stop2);
}
Sofar so good, the issue is that I want to reuse that triangle shape and give it another color. Overwriting the CSS variables has no effect! 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>
Expected Result:
I wished for a second triangle colored in a different way.
Result:
But I t seems like once the gradient is used, there is no way of modifying/overwriting it. It feels like that the gradient only takes value directly assigned to it which cannot be changed after using it. It may be due to the nature of the usage of the fill referencing an ID, but I am not sure
What I have tried / credit:
I checked SVG gradient using CSS which is where I got and modified the example from. (Thx to @Maciej-Kwas)
Additionally I am aware that you can inherit fill and use currentColor to provide more colors to an element that is "used". But up to this point I could not get this to work with a gradient yet.
Unsatisfying Workaround:
Since my goal is to keep the colors outside of the markup I could move the svg to the css inline as a data-Uri much like this:
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")
Big credit for the article about this: https://fvsch.com/svg-gradient-fill/
But since this only works in Firefox and seems hacky.
Closing thoughts:
I wonder if there is any other solution. And would like to know exactly why it does not work as I expected, in the first place, in detail.
Two observations:
You need to define 2 gradients and choose which one with a variable: fill: var(--grd);
You don't fill the <polygon>
you need to reuse. You fill the <use>
element.
I hope it helps.
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>