Home > Net >  Hover effect on SVG stop-color not respecting css selectors rules
Hover effect on SVG stop-color not respecting css selectors rules

Time:06-15

I try to add a hover effect on a link with a SVG as a child. I would like to change the stop-color of the svg when the link is hovered.

But now, all of the SVGs icon change the stop color when I hover the first .link element. If I hover the second or thrid .link element, the stop color will not change. How can I solve this problem without adding extra classes or js in the svg component?

Problem: enter image description here

hover the first one: enter image description here

hover the second one: enter image description here

codepen example

The class defines with scss and it looks like this:

.link {
  & defs stop:first-child {
    stop-color: #393896;
  }
  & defs stop:last-child {
    stop-color: #181735;
  }
  &:hover defs stop:first-child {
    stop-color: #ffbbcc;
  }
  &:hover defs stop:last-child {
    stop-color: #0000ff;
  }
  &:hover {
    background-color: red; // test to see if the css selector is working
  }
}

SVG:

<svg width="1em" height="1em" viewBox="0 0 84 115" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M41.977 0.397949C19.37 0.397949 0.869995 18.323 0.869995 40.242C0.869995 70.122 41.977 114.232 41.977 114.232C41.977 114.232 83.084 70.121 83.084 40.242C83.084 18.323 64.585 0.397949 41.977 0.397949ZM41.977 54.4689C40.0722 54.5265 38.1752 54.2011 36.3984 53.5119C34.6217 52.8227 33.0015 51.7838 31.6337 50.4568C30.266 49.1297 29.1786 47.5416 28.436 45.7865C27.6935 44.0315 27.3108 42.1452 27.3108 40.2394C27.3108 38.3337 27.6935 36.4474 28.436 34.6924C29.1786 32.9373 30.266 31.3492 31.6337 30.0221C33.0015 28.6951 34.6217 27.6562 36.3984 26.967C38.1752 26.2778 40.0722 25.9524 41.977 26.0099C43.8818 25.9524 45.7788 26.2778 47.5555 26.967C49.3323 27.6562 50.9525 28.6951 52.3203 30.0221C53.688 31.3492 54.7754 32.9373 55.518 34.6924C56.2605 36.4474 56.6431 38.3337 56.6431 40.2394C56.6431 42.1452 56.2605 44.0315 55.518 45.7865C54.7754 47.5416 53.688 49.1297 52.3203 50.4568C50.9525 51.7838 49.3323 52.8227 47.5555 53.5119C45.7788 54.2011 43.8818 54.5265 41.977 54.4689" fill="url(#paint0_linear_1_4257)" />
  <defs>
    <linearGradient id="paint0_linear_1_4257" x1="41.977" y1="0.397949" x2="41.977" y2="114.232" gradientUnits="userSpaceOnUse">
      <stop stop-color="currentColor" />
      <stop offset="1" stop-color="currentColor" />
    </linearGradient>
  </defs>
</svg>

And the html structure look like this:

<div id="main">
  <a >
    <svg ...  />
  </a>
  <a >
    <svg ... />
  </a>
</div>

I hope there would be a solution which also applies to scss module in a react project. Thank you

CodePudding user response:

Looking at your CodePen, it appears you copied the same SVG element for the second one. Because of that, both elements have the same id attribute value for the linearGradient element: paint0_linear_1_4257. That can cause some quirky behavior in SVG.

I'm guessing the path's fill directive (which takes the id as a parameter) is triggering all the matching ids for the first's hover event with some quirkiness in having multiple matching ids on a page not causing it to happen for any of those copied links after.

Easiest way to fix is to just ensure all id's on a page are unique. I renamed the first id to paint0_linear_1_4257_1 and the second to paint0_linear_1_4257_2, including updating the corresponding values in the fill directives, and that appears to have resolved the issue on my end.

CodePudding user response:

You can use CSS custom properties (variables) to change the colors. It is a bit tricky because you should not reuse IDs (your initial inline SVG element has the same linearGradient defined twice). Therefore I use the <symbol> element and place the linearGradient inside it. Now the same symbol can be reused and either the currentColor or a CSS variable can be used to change colors.

.link {
  color: red;
}

.link svg {
  width: 4em;
  height: 4em;
  --stop01: currentColor;
  --stop02: currentColor;
}

.link:hover svg {
  --stop01: #ffbbcc;
  --stop02: #0000ff;
}
<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
  <symbol id="marker" viewBox="0 0 84 115">
    <path d="M41.977 0.397949C19.37 0.397949 0.869995 18.323 0.869995 40.242C0.869995 70.122 41.977 114.232 41.977 114.232C41.977 114.232 83.084 70.121 83.084 40.242C83.084 18.323 64.585 0.397949 41.977 0.397949ZM41.977 54.4689C40.0722 54.5265 38.1752 54.2011 36.3984 53.5119C34.6217 52.8227 33.0015 51.7838 31.6337 50.4568C30.266 49.1297 29.1786 47.5416 28.436 45.7865C27.6935 44.0315 27.3108 42.1452 27.3108 40.2394C27.3108 38.3337 27.6935 36.4474 28.436 34.6924C29.1786 32.9373 30.266 31.3492 31.6337 30.0221C33.0015 28.6951 34.6217 27.6562 36.3984 26.967C38.1752 26.2778 40.0722 25.9524 41.977 26.0099C43.8818 25.9524 45.7788 26.2778 47.5555 26.967C49.3323 27.6562 50.9525 28.6951 52.3203 30.0221C53.688 31.3492 54.7754 32.9373 55.518 34.6924C56.2605 36.4474 56.6431 38.3337 56.6431 40.2394C56.6431 42.1452 56.2605 44.0315 55.518 45.7865C54.7754 47.5416 53.688 49.1297 52.3203 50.4568C50.9525 51.7838 49.3323 52.8227 47.5555 53.5119C45.7788 54.2011 43.8818 54.5265 41.977 54.4689" fill="url(#paint0)" />
    <defs>
      <linearGradient id="paint0" x1="41.977" y1="0.397949" x2="41.977" y2="114.232" gradientUnits="userSpaceOnUse">
        <stop style="stop-color: var(--stop01)" />
        <stop offset="1" style="stop-color: var(--stop02)" />
      </linearGradient>
    </defs>
  </symbol>
</svg>

<div id="main">
  <a >
    <svg xmlns="http://www.w3.org/2000/svg">
      <use href="#marker"/>
    </svg>
  </a>
  <a >
    <svg xmlns="http://www.w3.org/2000/svg">
      <use href="#marker"/>
    </svg>
  </a>
</div>

  • Related