:当 svg 在外部文件中时,悬停不在 svg 上工作

:hover not working on svg when svg is in external file

所以我正在学习 SVG 动画。

基本上我想做的就是在鼠标悬停时更改圆圈的颜色。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 viewBox="0 0 437.1 294.4" style="enable-background:new 0 0 437.1 294.4;" xml:space="preserve">

    <style type="text/css">

        .st0:hover {
            fill: red;
         }

    </style>

    <g id="Circle">
        <path class="st0" d="M291.3,147.4c0,77-62.4,139.4-139.4,139.4S12.5,224.4,12.5,147.4C12.6,70.4,75,8,151.9,8
        C228.9,8,291.3,70.4,291.3,147.4"/>
    </g>

</svg>

当 svg 代码在 html 文件中时,这完全符合预期。

但是,当我将它放入 svg 文件并使用 img 标签调用它时,悬停效果不再有效。

<img class="logo" src="url/logo.svg">

有没有办法在不将 svg 代码嵌入 html 的情况下做到这一点?

谢谢!

无法使用 <img> 标签完成。参见:Styling And Animating SVGs With CSS。在本文页面底部附近有一个 table,其中列出了每种 SVG 嵌入技术(即 img、对象等)的优缺点。我在这里转载了 table:

|                      | CSS Interactions | CSS Animations | SVG Animations |
|:--------------------:|:----------------:|:--------------:|:--------------:|
|         <img>        |        No        |      Yes*      |       Yes      |
| CSS background image |        No        |      Yes*      |       Yes      |
|       <object>       |       Yes*       |      Yes*      |       Yes      |
|       <iframe>       |       Yes*       |      Yes*      |       Yes      |
|        <embed>       |       Yes*       |      Yes*      |       Yes      |
|    <svg> (inline)    |        Yes       |       Yes      |       Yes      |

*仅在 <svg>

我把这个答案写成 的一种应用版本。以下代码段显示了您可以如何利用的不同形式 <svg> 以及它们在每种情况下的功能。

主要要点是,根据上下文,<svg> 可能会或可能不会从顶级文档接收样式规则,并且可能会或可能不会从顶级文档接收交互事件(:hover).

我建议您查看下面的代码片段以查看正在运行的应用程序:

const someSVG = `
<svg width="128" height="128" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <style>
        .interactive.from-svg {
            fill: red;
            transition: fill 200ms ease;
        }

        .interactive.from-svg:hover {
            fill: blue;
        }

        .animated.from-svg{
            animation: 3s infinite alternate changecolor;
        }

        @keyframes changecolor{
            from {
                fill: green;
            }
            to {
                fill: purple;
            }
        }
    </style>
    <circle class="interactive from-doc" cx="25" cy="25" r="25"></circle>
    <circle class="animated from-doc" cx="75" cy="25" r="25"></circle>
    <circle class="interactive from-svg" cx="25" cy="75" r="25"></circle>
    <circle class="animated from-svg" cx="75" cy="75" r="25"></circle>
</svg>
`;
const dataUri = `data:image/svg+xml;base64,${btoa(someSVG)}`;

const imgContainer = document.getElementById("img-container"),
  img = document.createElement("img");
imgContainer.appendChild(img);
img.src = dataUri;

const backgroundImageContainer = document.getElementById("background-image-container"),
  backgroundImage = document.createElement("div");
backgroundImageContainer.appendChild(backgroundImage);
backgroundImage.style.width = "128px";
backgroundImage.style.height = "128px";
backgroundImage.style.backgroundImage = `url(${dataUri})`;

const iframeContainer = document.getElementById("iframe-container"),
  iframe = document.createElement("iframe");
iframeContainer.appendChild(iframe);
iframe.src = dataUri;
main {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

section {
  flex-basis: 50%;
  flex-grow: 1;
  flex-shrink: 0;
}

.interactive.from-doc {
  fill: red;
  transition: fill 200ms ease;
}

.interactive.from-doc:hover {
  fill: blue;
}

.animated.from-doc {
  animation: 3s infinite alternate changecolor;
}

@keyframes changecolor {
  from {
    fill: green;
  }
  to {
    fill: purple;
  }
}

li.pro {
  color: green;
}

li.con {
  color: red;
}
<h1><code>&lt;svg&gt;</code> Usage Comparison</h1>
<main>
  <section id="external">
    <h2><code>&lt;img&gt;</code></h2>
    <div id="img-container"></div>
    <pre><code>&lt;img src="some.svg"&gt;</code></pre>
    <ul>
      <li class="con">Does not receive <strong>any</strong> style from top level document</li>
      <li class="con">Does not utilize CSS Interactions such as <code>:hover</code></li>
      <li class="pro">Will use CSS Animations if they are defined within the svg element's style</li>
    </ul>
  </section>
  <section>
    <h2><code>background-image</code></h2>
    <div id="background-image-container"></div>
    <pre><code>
&lt;style&gt;
.rule{
    background-image: url(some.svg);
}
&lt;/style&gt;
&lt;div class="rule"&gt;&lt;/div&gt;
</code></pre>
    <ul>
      <li class="con">Does not receive <strong>any</strong> style from top level document</li>
      <li class="con">Does not utilize CSS Interactions</li>
      <li class="pro">Will use CSS Animations if they are defined within the svg element's style</li>
    </ul>
  </section>
  <section>
    <h2><code>&lt;iframe&gt;</code></h2>
    <div id="iframe-container"></div>
    <pre><code>&lt;iframe src="some.svg"&gt;</code></pre>
    <ul>
      <li class="con">Does not receive <strong>any</strong> style from top level document</li>
      <li class="pro">Will use CSS Interactions if they are defined within the svg element's style</li>
      <li class="pro">Will use CSS Animations if they are defined within the svg element's style</li>
    </ul>
  </section>
  <section>
    <h2>Inline <code>&lt;svg&gt;</code></h2>
    <svg width="128" height="128" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
                <style>
                    .interactive.from-svg {
                        fill: red;
                        transition: fill 200ms ease;
                    }

                    .interactive.from-svg:hover {
                        fill: blue;
                    }

                    .animated.from-svg{
                        animation: 3s infinite alternate changecolor;
                    }

                    @keyframes changecolor{
                        from {
                            fill: green;
                        }
                        to {
                            fill: purple;
                        }
                    }
                </style>
                <circle class="interactive from-doc" cx="25" cy="25" r="25"></circle>
                <circle class="animated from-doc" cx="75" cy="25" r="25"></circle>
                <circle class="interactive from-svg" cx="25" cy="75" r="25"></circle>
                <circle class="animated from-svg" cx="75" cy="75" r="25"></circle>
            </svg>
    <pre><code>&lt;svg&gt;...&lt;/svg&gt;</code></pre>
    <ul>
      <li class="pro">Receives <strong>all</strong> style rules from top level document</li>
      <li class="pro">Will use CSS Interactions if they are defined within the svg element's style</li>
      <li class="pro">Will use CSS Animations if they are defined within the svg element's style</li>
    </ul>
  </section>
</main>

<img>

<img src="some.svg">
  • 未从顶级文档
  • 接收任何样式
  • 不利用 CSS 交互,例如 :hover
  • 将使用 CSS 动画,如果它们是在 svg 元素的样式中定义的

background-image

<style>
.rule {
    background-image: url(some.svg);
}
</style>
<div class="rule"></div>
  • 未从顶级文档
  • 接收任何样式
  • 不利用 CSS 互动
  • 将使用 CSS 动画,如果它们是在 svg 元素的样式中定义的

<iframe>

<iframe src="some.svg"></iframe>
  • 没有从顶级文档中接收到任何样式
  • 将使用 CSS 交互,如果它们是在 svg 元素的样式中定义的
  • 将使用 CSS 动画,如果它们是在 svg 元素的样式中定义的

内联<svg>

<svg>...</svg>
  • 从顶级文档接收所有样式规则
  • 将使用 CSS 交互,如果它们是在 svg 元素的样式中定义的
  • 将使用 CSS 动画,如果它们是在 svg 元素的样式中定义的