Home > Software engineering >  SVG – :hover and links are not working in combination with clip-path and Firefox
SVG – :hover and links are not working in combination with clip-path and Firefox

Time:11-11

For some reason, :hover and links are not working in combination with clip-path in Firefox. No problem with Chrome. I need clip-path to work. I know that it works without the attribute. However, it's not an option for me to remove this attribute.

Any idea why?


Simplified example:

<svg xmlns="http://www.w3.org/2000/svg" height="210" width="400">
  <style>
    path {
      fill: blue;
    }

    path:hover {
      fill: red;
    }
  </style>
  <a target="_parent" href="/test">
    <path id="triangle" clip-path="url('#triangle-clip')" d="M150 0 L75 200 L225 200 Z">
      <title>Triangle</title>
    </path>
  </a>
  <clipPath id="triangle-clip">
    <use href="#triangle" />
  </clipPath>
</svg>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

We need to break the recursion here that makes the whole thing invalid. I.e. in the version in the question the clip-path points to a <use> element that points to a <path> that has a clip-path that points to a <use> that points to a <path>...

Here's one way i.e. apply the clip-path only to the path when it's a descendant of the <a> element. That's ignored by the <use> element because the selector crosses the shadow DOM boundary.

Another way would be to replace the <use> element with a copy of the <path> its pointing to and remove the clip-path from that copy of the path, and so again fix the infinite recursion problem.

<svg xmlns="http://www.w3.org/2000/svg" height="210" width="400">
  <style>
    path {
      fill: blue;
    }

    path:hover {
      fill: red;
    }
    a > path {
      clip-path: url('#triangle-clip');
    }
  </style>
  <a target="_parent" href="/test">
    <path id="triangle" d="M150 0 L75 200 L225 200 Z">
      <title>Triangle</title>
    </path>
  </a>
  <clipPath id="triangle-clip">
    <use href="#triangle" />
  </clipPath>
</svg>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

In your case clip-path does nothing, so I just removed it. ANd it's important to add @namespace.

@namespace svg url(http://www.w3.org/2000/svg);
svg|a path {
    fill: blue;
}

svg|a:hover path {
    fill: red;
}
<svg xmlns="http://www.w3.org/2000/svg" height="210" width="400">
  <a href="/test">
    <path id="triangle" d="M150 0 L75 200 L225 200 Z">
      <title>Triangle</title>
    </path>
  </a> 
</svg>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

I noticed that if you open developer tools in Firefox you will see that you have a shadow-root (closed) whereas in Chrome you do not. That could possibly be why your :hover Pseudo-class isn't executing.

https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/mode

CodePudding user response:

As @Robert Longson has pointed out your initial code has a recursion issue.

Essentially, you are clipping an svg path (triangle) by itself (... that still has to be defined by itself) – resulting in the exact same shape as the 'unclipped' version.

However, since you already used the <use> element, reordering your path and clipping path definitions - avoiding unnessesary recursions – might still simplify your app's code.

<svg xmlns="http://www.w3.org/2000/svg" height="210" width="400">
  <clipPath id="triangle-clip">
    <path id="triangle-path" d="M150 0 L75 200 L225 200 Z" />
  </clipPath>
  <style>
    .link-content {
      fill: blue;
        clip-path: url('#triangle-clip');
    }
    a:hover .link-content{
      fill: red;
    }
  </style>
  <a class="link" target="_parent" href="/test">
    <title>Triangle</title>
    <use class="link-content" href="#triangle-path" />
  </a>
</svg>
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related