SVG gradient using CSS
Solution 1
Just use in the CSS whatever you would use in a fill
attribute.
Of course, this requires that you have defined the linear gradient somewhere in your SVG.
Here is a complete example:
rect {
cursor: pointer;
shape-rendering: crispEdges;
fill: url(#MyGradient);
}
<svg width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
rect{fill:url(#MyGradient)}
</style>
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="#F60" />
<stop offset="95%" stop-color="#FF6" />
</linearGradient>
</defs>
<rect width="100" height="50"/>
</svg>
Solution 2
2019 Answer
With brand new css properties you can have even more flexibility with variables aka custom properties
.shape {
width:500px;
height:200px;
}
.shape .gradient-bg {
fill: url(#header-shape-gradient) #fff;
}
#header-shape-gradient {
--color-stop: #f12c06;
--color-bot: #faed34;
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" class="shape">
<defs>
<linearGradient id="header-shape-gradient" x2="0.35" y2="1">
<stop offset="0%" stop-color="var(--color-stop)" />
<stop offset="30%" stop-color="var(--color-stop)" />
<stop offset="100%" stop-color="var(--color-bot)" />
</linearGradient>
</defs>
<g>
<polygon class="gradient-bg" points="0,0 100,0 0,66" />
</g>
</svg>
Just set a named variable for each stop
in gradient and then customize as you like in css. You can even change their values dynamically with javascript, like:
document.querySelector('#header-shape-gradient').style.setProperty('--color-stop', "#f5f7f9");
Solution 3
Building on top of what Finesse wrote, here is a simpler way to target the svg and change it's gradient.
This is what you need to do:
- Assign classes to each color stop defined in the gradient element.
- Target the css and change the stop-color for each of those stops using plain classes.
- Win!
Some benefits of using classes instead of :nth-child
is that it'll not be affected if you reorder your stops. Also, it makes the intent of each class clear - you'll be left wondering whether you needed a blue color on the first child or the second one.
I've tested it on all Chrome, Firefox and IE11:
.main-stop {
stop-color: red;
}
.alt-stop {
stop-color: green;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop class="main-stop" offset="0%" />
<stop class="alt-stop" offset="100%" />
</linearGradient>
<rect width="100" height="50" fill="url(#gradient)" />
</svg>
See an editable example here: https://jsbin.com/gabuvisuhe/edit?html,css,output
Solution 4
Here is a solution where you can add a gradient and change its colours using only CSS:
// JS is not required for the solution. It's used only for the interactive demo.
const svg = document.querySelector('svg');
document.querySelector('#greenButton').addEventListener('click', () => svg.setAttribute('class', 'green'));
document.querySelector('#redButton').addEventListener('click', () => svg.setAttribute('class', 'red'));
svg.green stop:nth-child(1) {
stop-color: #60c50b;
}
svg.green stop:nth-child(2) {
stop-color: #139a26;
}
svg.red stop:nth-child(1) {
stop-color: #c84f31;
}
svg.red stop:nth-child(2) {
stop-color: #dA3448;
}
<svg class="green" width="100" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="gradient">
<stop offset="0%" />
<stop offset="100%" />
</linearGradient>
<rect width="100" height="50" fill="url(#gradient)" />
</svg>
<br/>
<button id="greenButton">Green</button>
<button id="redButton">Red</button>
Solution 5
Thank you everyone, for all your precise replys.
Using the svg in a shadow dom, I add the 3 linear gradients I need within the svg, inside a . I place the css fill rule on the web component and the inheritance od fill does the job.
<svg viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path
d="m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z"></path>
</svg>
<svg height="0" width="0">
<defs>
<linearGradient id="lgrad-p" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#4169e1"></stop><stop offset="99%" stop-color="#c44764"></stop></linearGradient>
<linearGradient id="lgrad-s" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#ef3c3a"></stop><stop offset="99%" stop-color="#6d5eb7"></stop></linearGradient>
<linearGradient id="lgrad-g" gradientTransform="rotate(75)"><stop offset="45%" stop-color="#585f74"></stop><stop offset="99%" stop-color="#b6bbc8"></stop></linearGradient>
</defs>
</svg>
<div></div>
<style>
:first-child {
height:150px;
width:150px;
fill:url(#lgrad-p) blue;
}
div{
position:relative;
width:150px;
height:150px;
fill:url(#lgrad-s) red;
}
</style>
<script>
const shadow = document.querySelector('div').attachShadow({mode: 'open'});
shadow.innerHTML="<svg viewbox=\"0 0 512 512\">\
<path d=\"m258 0c-45 0-83 38-83 83 0 45 37 83 83 83 45 0 83-39 83-84 0-45-38-82-83-82zm-85 204c-13 0-24 10-24 23v48c0 13 11 23 24 23h23v119h-23c-13 0-24 11-24 24l-0 47c0 13 11 24 24 24h168c13 0 24-11 24-24l0-47c0-13-11-24-24-24h-21v-190c0-13-11-23-24-23h-123z\"></path>\
</svg>\
<svg height=\"0\">\
<defs>\
<linearGradient id=\"lgrad-s\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#ef3c3a\"></stop><stop offset=\"99%\" stop-color=\"#6d5eb7\"></stop></linearGradient>\
<linearGradient id=\"lgrad-g\" gradientTransform=\"rotate(75)\"><stop offset=\"45%\" stop-color=\"#585f74\"></stop><stop offset=\"99%\" stop-color=\"#b6bbc8\"></stop></linearGradient>\
</defs>\
</svg>\
";
</script>
The first one is normal SVG, the second one is inside a shadow dom.
Comments
-
Hrishikesh Choudhari over 3 years
I'm trying to get a gradient applied to an SVG
rect
element.Currently, I'm using the
fill
attribute. In my CSS file:rect { cursor: pointer; shape-rendering: crispEdges; fill: #a71a2e; }
And the
rect
element has the correct fill color when viewed in the browser.However, I'd like to know if I can apply a linear gradient to this element?
-
Hrishikesh Choudhari over 11 yearsSo I created that gradient in a separate file, and used
fill
this way:fill: url(../js/gradient.svg#MyGradient);
. Is this the right way? -
Thomas W over 11 years@HrishikeshChoudhari: Yes, this is correct, but Chrome and I think Safari as well don't support referencing elements from other files. Not sure about IE9 (can't test right now, just give it a try).
-
Arthur Weborg about 9 yearsTo anyone who reads this and asks "what about
fill: linear-gradient (...)
?"fill
requires a<paint>
which is built around the CSS2<color>
class. In other words, this answer is currently the only way to do it via CSS at the time I am writing this comment. You need to add alinearGradient
element. Lastly, going through the w3 Working Draft for SVG2, it appears support forlinear-gradient
on the fill css rule has not and might not make it into the spec. -
AGamePlayer over 7 yearsHow to change the direction in this case?
-
Thomas W over 7 years@AwQiruiGuo Have a look at MDN (specifically the
gradientTransform
attribute) -
Chris Rae about 6 yearsJust to answer Marten's comment - this works fine in Chrome if the SVG is defined in the same file that you're intending using it from. It (apparently) does not work if you use the blah.svg#MyGradient notation that Hrishikesh mentioned.
-
ACJ over 5 yearsNothing in the question implies use of php.
-
aoakeson about 5 yearsNot supported In IE.
-
Finesse almost 5 yearsThe lack is that you don't know for sure what the stop class names are and what order they have. Actually, the solutions are the same good, the only difference is the CSS selectors.
-
Finesse over 4 years@MaciejKwas, you are wrong. Old browsers don't stay forever so companies who are not ready now will be ready then. And if somebody isn't ready to discard a portion of his audience, it doesn't mean that he isn't ready for changes, it means he prefers to leverage the changes later to keep a bigger audience.
-
Ciprian over 4 years@aoakeson IE is dead. End of lifed. Edge is also dying, this is a 2019 answer, so IE shouldn't count. IE can degrade gracefully by using a solid colour.
-
James Martin-Davies over 4 years@aoakeson I'm amazingly surprised to come across that kind of response in 2019. You'd be naive as a developer to assume SVG support in IE on this level would ever be supported, let alone a budding developer on SO giving you a bloated, polyfilled answer for something unnecessarily needed if you intend to support IE.