SVG文件或标签中如何添加hover样式

6

我有一个SVG标签,我想在鼠标悬停时更改填充颜色。我在SVG标签内添加了样式标签,但似乎hover不起作用,而简单的样式却可以正常工作。这是我的SVG标签:

<svg width="28" height="81" viewBox="0 0 28 81" xmlns="http://www.w3.org/2000/svg">
    <style type="text/css">
        .slick_next_arrow {
            fill:red;
         }
        .slick_next_arrow:hover {
            fill:green;
         }
     </style>
     <path class="slick_next_arrow" hover="fill:green" fill-rule="evenodd" clip-rule="evenodd" d="M3.73141 1.20959C2.95311 -0.00927037 1.3341 -0.366415 0.115239 0.411883L25.5894 40.3058L0 80.3802C1.21886 81.1585 2.83787 80.8014 3.61617 79.5825L27.4729 42.2216C27.7642 41.7653 27.8965 41.2531 27.884 40.7498C28.1017 40.0409 28.0185 39.2445 27.5881 38.5705L3.73141 1.20959Z"/>
</svg>

我已将此svg包含在元素:::after 中,两种方式均可:
  1. Adding the whole tag inside content

    #slick-views-customer-quotes-carousel-block-main-1 .slick__arrow .slick-next::after {
       content : url('data:image/svg+xml; utf8, <svg class="" width="28" height="81" viewBox="0 0 28 81" xmlns="http://www.w3.org/2000/svg">  <style type="text/css">  .slick_next_arrow {      fill:blue;  }  .slick_next_arrow:hover {      fill:green;  }  </style>  <path class="slick_next_arrow" hover="fill:green" fill-rule="evenodd" clip-rule="evenodd" d="M3.73141 1.20959C2.95311 -0.00927037 1.3341 -0.366415 0.115239 0.411883L25.5894 40.3058L0 80.3802C1.21886 81.1585 2.83787 80.8014 3.61617 79.5825L27.4729 42.2216C27.7642 41.7653 27.8965 41.2531 27.884 40.7498C28.1017 40.0409 28.0185 39.2445 27.5881 38.5705L3.73141 1.20959Z"/></svg>');
    

    }

  2. as separate SVG file

    #slick-views-customer-quotes-carousel-block-main-1 .slick__arrow .slick-next::after {
       content : url("../images/right_arrow.svg");
    }
    
但是它们都没有起作用。有什么方法可以解决这个问题吗?

1
你能测试一下这个代码吗?#slick-views-customer-quotes-carousel-block-main-1 .slick__arrow svg:hover path { fill: #0058A7; } - Naser Nikzad
@NaserNikzad,它不起作用。 - Ahmad Karimi
1
@NaserNikzad,您的解决方案在直接在DOM中使用<svg>元素时运行良好。但是,在问题中,它被用作伪元素的内容。因此,我们无法直接访问<svg>标签以应用样式。 - Mohandes
2个回答

5
当您将其设置为伪元素的内容时,您的svg实际上是CSS <image>。表示svg文档的CSS <image>与表示svg的html <img>具有相同的限制
  • 不会获取任何外部资源
  • 脚本不会在内部文档中运行
  • 内部文档不会交互(即没有指针事件)
  • ...
这意味着此svg文档中的任何:hover样式都将无效。
但是,您可以在父级.slick-next元素上设置此:hover并在那里更改content
为了避免在服务器上存储两个svg文件,只更改fill,您可以使用一个由Lea Verou演示的hack,它利用了:target伪类。这里有更多信息
您需要重新构造svg,以便具有[id]属性的不可见触发器元素可以成为:target。然后,所有逻辑都使用CSS选择器实现:

right_arrow.svg

<svg width="28" height="81" viewBox="0 0 28 81" xmlns="http://www.w3.org/2000/svg">
  <style>
    .slick_next_arrow {
      fill:red;
    }
    /* when loaded from 'right_arrow.svg#hover' */
    #hover:target ~ .slick_next_arrow {
      fill:green;
    }
  </style>
  <!-- here is our triggerer -->
  <g id="hover"></g>
  <!-- the visual content -->
  <path class="slick_next_arrow" hover="fill:green" fill-rule="evenodd" clip-rule="evenodd" d="M3.73141 1.20959C2.95311 -0.00927037 1.3341 -0.366415 0.115239 0.411883L25.5894 40.3058L0 80.3802C1.21886 81.1585 2.83787 80.8014 3.61617 79.5825L27.4729 42.2216C27.7642 41.7653 27.8965 41.2531 27.884 40.7498C28.1017 40.0409 28.0185 39.2445 27.5881 38.5705L3.73141 1.20959Z"/>
</svg>

以及你的CSS:

.slick__arrow .slick-next::after {
  content : url('right_arrow.svg');
}
.slick__arrow .slick-next:hover::after {
  content : url('right_arrow.svg#hover');
}

这是一个更加复杂的实时代码片段,因为我们必须解决无法从StackSnippets托管第三方文件的问题。

const svg_content = `<svg width="28" height="81" viewBox="0 0 28 81" xmlns="http://www.w3.org/2000/svg">
  <style>
    .slick_next_arrow {
      fill:red;
    }
    #hover:target ~ .slick_next_arrow {
      fill:green;
    }
/* some goodies */
    circle {
      display: none;
    }
    /* hide previous path */
    [id^="show_circle"]:target ~ .slick_next_arrow {
      display: none;
    }
    /* show new one */
    [id^="show_circle"]:target ~ circle {
      display: block; 
      fill: red;
    }
    #show_circle_hover:target ~ circle.change-color {
      fill: green;
    }
  </style>
  <!-- here are all our triggerers -->
  <g id="hover"></g>
  <g id="show_circle"></g>
  <g id="show_circle_hover"></g>
  <path class="slick_next_arrow" hover="fill:green" fill-rule="evenodd" clip-rule="evenodd" d="M3.73141 1.20959C2.95311 -0.00927037 1.3341 -0.366415 0.115239 0.411883L25.5894 40.3058L0 80.3802C1.21886 81.1585 2.83787 80.8014 3.61617 79.5825L27.4729 42.2216C27.7642 41.7653 27.8965 41.2531 27.884 40.7498C28.1017 40.0409 28.0185 39.2445 27.5881 38.5705L3.73141 1.20959Z"/>
  <circle cx="14" cy="15" r="12"/>
  <circle cx="14" cy="40" r="12" class="change-color"/>
  <circle cx="14" cy="65" r="12"/>
</svg>`;

// StackSnippets force us to make a complex js-powered live demo...
// but in production all is done from CSS
const url = URL.createObjectURL( new Blob( [ svg_content ], { type: "image/svg+xml" } ) );

const el = document.querySelector( '.parent' );
el.style.setProperty( '--url', 'url(' + url + ')' );
el.style.setProperty( '--url-hovered', 'url(' + url + '#hover)' );
el.style.setProperty( '--url-circle', 'url(' + url + '#show_circle)' );
el.style.setProperty( '--url-circle-hovered', 'url(' + url + '#show_circle_hover)' );
.parent{
  display: inline-block;
  width: 28px;
  height: 90px;
}
.parent::before {
  /* right_arrow.svg */
  content: var(--url);
}
.parent:hover::before {
  /* right_arrow.svg#hover */
  content: var(--url-hovered);
}
/* goodies */
:checked ~ .parent::before {
  /* right_arrow.svg#show_circle */
  content: var(--url-circle);
}
:checked ~ .parent:hover::before {
  /* right_arrow.svg#show_circle_hover */
  content: var(--url-circle-hovered);
}
<input type="checkbox" id="check"><label for="check">change shape</label><br>
<div class="parent"></div>

但您可以在此plnkr中访问简化版本。


答案不错,但我需要尽一切办法避免使用JavaScript。我需要纯CSS实现。 - Ahmad Karimi
@AhmadKarimi 我在代码片段中使用JavaScript,只是因为StackSnippets不允许存储第三方资源。请查看答案底部的plnkr,那里没有任何js。 - Kaiido
我正要将这个解决方案作为答案写下来,而不是更改路径填充颜色(当用作伪元素内容时似乎不可能),您可以只需更改:before元素的内容,使用相同的SVG但不同的填充颜色。好主意@Kaiido! - Mohandes

1
你可以考虑使用过滤器来改变颜色:

.box {
 content : url('data:image/svg+xml; utf8, <svg class="" width="28" height="81" viewBox="0 0 28 81" xmlns="http://www.w3.org/2000/svg"> <path class="slick_next_arrow" fill="green" fill-rule="evenodd" clip-rule="evenodd" d="M3.73141 1.20959C2.95311 -0.00927037 1.3341 -0.366415 0.115239 0.411883L25.5894 40.3058L0 80.3802C1.21886 81.1585 2.83787 80.8014 3.61617 79.5825L27.4729 42.2216C27.7642 41.7653 27.8965 41.2531 27.884 40.7498C28.1017 40.0409 28.0185 39.2445 27.5881 38.5705L3.73141 1.20959Z"/></svg>')
}
.box:hover {
  filter:hue-rotate(250deg);
}
<div class="box">
</div>

相关:在CSS中内联SVG图像

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接