naregjan
naregjan

Reputation: 35

transitioning SVG gradient color-stops on hover

So I've got this CodePen: https://codepen.io/naregjan/pen/MBzQWp

In it, I've got four rects inside of an SVG frame, and two of them have gradients. I want to transition the stop colours for the gradients on hover, similarly to this pen.

The relevant CSS:

.red{
  fill: url(#grad1);
}
.red ~ defs stop{
  transition: 1s;
}
.red:hover ~ defs stop:first-child {
  stop-color: #ffbbcc;
}
.red:hover ~ defs stop:last-child {
  stop-color: #0000ff;
}

And the relevant HTML (the squares are generated via JS; this is via the Chrome Inspector):

<svg id="sqSVG" width="500" height="500">
  <rect class="square green" x="135" y="135" width="100" height="100"></rect>
  <rect class="square green" x="10" y="135" width="100" height="100"></rect
  <rect class="square red" x="135" y="10" width="100" height="100"></rect>
  <rect class="square red" x="10" y="10" width="100" height="100"></rect>
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="110%" y2="110%">
      <stop offset="0%" style="stop-color:#ff0000"></stop>
      <stop offset="100%" style="stop-color:#ffffff"></stop>
    </linearGradient>
  </defs>
</svg>

I can't figure out what's wrong. It won't just not animate, it won't change the stop colour on hover at all, and I can't figure out what's different from the example I linked. The rects are created before defs and they share a parent, so the selector should work... what am I missing?

In case it's relevant, here's my square-making function:

function makeSquares(){
  var svg = document.querySelector("#sqSVG");

  var squares = [
    {x : "10", y : "10", color: "red"},
    {x : "135", y : "10", color: "red"},
    {x : "10", y : "135", color: "green"},
    {x : "135", y : "135", color: "green"}
  ];

  squares.forEach(sq => {
    var newSq = document.createElementNS("http://www.w3.org/2000/svg", 'rect');
    newSq.setAttribute("class", "square " + sq.color);
    newSq.setAttribute("x", sq.x);
    newSq.setAttribute("y", sq.y);
    newSq.setAttribute("width", "100");
    newSq.setAttribute("height", "100");
    svg.prepend(newSq);
  });
}

... but I don't think it is, because it won't work while hard-coded in HTML, either. Help?

Upvotes: 3

Views: 1685

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101800

As @Kaiido said, you are being thwarted because style attributes override CSS. So your hover rules were having no effect.

The fix is to change them to attributes. Change

style="stop-color:#ffffff"

to

stop-color="#ffffff"

In addition, you had a typo. </rect should be </rect> in the second rectangle.

.red{
  fill: url(#grad1);
}
.red ~ defs stop{
  transition: 1s;
}
.red:hover ~ defs stop:first-child {
  stop-color: #ffbbcc;
}
.red:hover ~ defs stop:last-child {
  stop-color: #0000ff;
}
<svg id="sqSVG" width="500" height="500">
  <rect class="square green" x="135" y="135" width="100" height="100"></rect>
  <rect class="square green" x="10" y="135" width="100" height="100"></rect>
  <rect class="square red" x="135" y="10" width="100" height="100"></rect>
  <rect class="square red" x="10" y="10" width="100" height="100"></rect>
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="110%" y2="110%">
      <stop offset="0%" stop-color="#ff0000"></stop>
      <stop offset="100%" stop-color="#ffffff"></stop>
    </linearGradient>
  </defs>
</svg>

Upvotes: 4

Related Questions