SVG gradient using CSS

173,265

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:

  1. Assign classes to each color stop defined in the gradient element.
  2. Target the css and change the stop-color for each of those stops using plain classes.
  3. 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.

Share:
173,265
Hrishikesh Choudhari
Author by

Hrishikesh Choudhari

JavaScript and data visualization guy.

Updated on December 14, 2020

Comments

  • Hrishikesh Choudhari
    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
    Hrishikesh Choudhari over 11 years
    So 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
    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
    Arthur Weborg about 9 years
    To 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 a linearGradient element. Lastly, going through the w3 Working Draft for SVG2, it appears support for linear-gradient on the fill css rule has not and might not make it into the spec.
  • AGamePlayer
    AGamePlayer over 7 years
    How to change the direction in this case?
  • Thomas W
    Thomas W over 7 years
    @AwQiruiGuo Have a look at MDN (specifically the gradientTransform attribute)
  • Chris Rae
    Chris Rae about 6 years
    Just 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
    ACJ over 5 years
    Nothing in the question implies use of php.
  • aoakeson
    aoakeson about 5 years
    Not supported In IE.
  • Finesse
    Finesse almost 5 years
    The 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
    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
    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
    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.