:hover not working on svg when svg is in external

2019-03-01 01:33发布

So I'm learning SVG animation.

Basically all I'm trying to do is change the color of a circle when it's hovered over.

<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>

This works exactly as expected when the svg code is inside the html file.

However, when I put it inside an svg file and call it in using the img tag the hover effect no longer works.

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

Is there a way to do this without embedding the svg code inside the html?

Thanks!

2条回答
孤傲高冷的网名
2楼-- · 2019-03-01 01:56

I am writing this answer as a sort of applied version of Sean's answer. The following snippet shows varying forms of how you can utilize <svg> and what their capabilities are in each context.

The main takeaway is that depending on the context, the <svg> may or may not receive style rules from the top level document and may or may not receive interactive events from the top level document (:hover).

I suggest you view the snippet below to see the applications in action:

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">
  • Does not receive any style from top level document
  • Does not utilize CSS Interactions such as :hover
  • Will use CSS Animations if they are defined within the svg element's style

background-image

<style>
.rule {
    background-image: url(some.svg);
}
</style>
<div class="rule"></div>
  • Does not receive any style from top level document
  • Does not utilize CSS Interactions
  • Will use CSS Animations if they are defined within the svg element's style

<iframe>

<iframe src="some.svg"></iframe>
  • Does not receive any style from top level document
  • Will use CSS Interactions if they are defined within the svg element's style
  • Will use CSS Animations if they are defined within the svg element's style

inline <svg>

<svg>...</svg>
  • Receives all style rules from top level document
  • Will use CSS Interactions if they are defined within the svg element's style
  • Will use CSS Animations if they are defined within the svg element's style
查看更多
男人必须洒脱
3楼-- · 2019-03-01 02:06

Can't be done with the <img> tag. See: Styling And Animating SVGs With CSS. Near the bottom of the page of this article there's a table with the pros and cons of each SVG embedding technique (ie, img, object, etc.). I have reproduced the table here:

|                      | 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      |

*Only if inside <svg>

查看更多
登录 后发表回答