Home > Net >  SVG with marker having an issue on mouse over
SVG with marker having an issue on mouse over

Time:12-11

I have a button with svg inside like:

<button>
 Checkout
 <ArrowSvg />
</button>

And ArrowSvg looks like this (line has class: svg-line):

<svg fill="none" stroke="#000">
  <defs>
    <marker id="m" overflow="visible">
      <path d="M-4,-4L0,0 -4,4" />
    </marker>
  </defs>
  <line x1="0" y1="50%" x2="100%" y2="50%"marker-end="url(#m)"  />
</svg>


When button is hovered, I change the stroke color:

btn:hover > .svg-line {
  stroke: blue;
}

It's working well - when I hover the button, the arrow (line and arrow head) turns blue. But when I display the multiple buttons (more than 1), hovering 1 button affects arrows in other buttons. The arrow head part (which is marker/path in svg?) of all the buttons get affected when hovering the first button.
I am also working with the arrow width, so I need line. I can't make everything with path because I won't be able to expand the arrow width. Am I missing anything? Why am I seeing this issue?

CodePudding user response:

Wrap it in a native JS Web Component, supported in all modern browsers, to create the <svg>

  • because every SVG requires a unique marker ID

  • note: the SVG is created for every instance, no need for a marker at all, use the path by itself

customElements.define("svg-button",class extends HTMLElement{
  connectedCallback(){
    let id = "id"   (Math.floor(Math.random() * 1e10));
    let stroke = this.getAttribute("stroke") || "#000";
    this.innerHTML = `
          <button> 
           Checkout
            <svg fill="none" stroke="${stroke}" viewBox="0 0 10 10">
              <defs>
                <marker id="${id}" overflow="visible">
                  <path d="M-4,-4L0,0 -4,4"/>
                </marker>
              </defs>
              <line x1="0" y1="5" x2="9" y2="5" marker-end="url(#${id})"/>
            </svg>
          </button>`
    }
});
<style>
  button:hover svg {
    stroke:gold;
  }
</style>

<svg-button></svg-button>
<svg-button stroke="red"></svg-button>
<svg-button stroke="green"></svg-button>
<svg-button stroke="blue"></svg-button>

CodePudding user response:

What you are writing looks like .JSX syntax, but the question is lacking a react tag. I will assume it for this answer anyway, but other frameworks using the format will probably work comparably.

All you need is a unique id for the <marker> element. This is easily done if you spell out the <ArrowSvg> as a function. Then, wrap it in a factory function to form a closure over a running number:

const ArrowSvg = (() => {
  let id = 0;
  return function (props) {
    return (
      const ref = 'arrowMarker'     id;
      <svg fill="none" stroke="#000">
        <defs>
          <marker id=(ref) overflow="visible">
            <path d="M-4,-4L0,0 -4,4" />
          </marker>
        </defs>
        <line x1="0" y1="50%" x2="100%" y2="50%"
              marker-end=(`url(#${ref})`)  />
      </svg>
    );
  }
})();
  • Related