The hover effect does not function on an SVG element when it is placed within an external file

I've been experimenting with SVG animation.

My goal is to 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>

Everything works as expected when the svg code is directly in the html file.

However, when I move it into an external svg file and include it using the img tag, the hover effect stops working.

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

Is there a way to achieve this without embedding the svg code within the html?

Appreciate any help!

Answer №1

It is impossible to achieve using the <img> element. Check out this resource: Styling And Animating SVGs With CSS. Towards the end of the article, there is a comparison table outlining the advantages and disadvantages of different SVG embedding methods (such as img, object, etc.). Here is a snapshot of that 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      |

*Only applicable if nested within an <svg> element

Answer №2

Inspired by Sean's response, I have crafted this answer to showcase practical applications of utilizing the <svg> element and its capabilities in various contexts.

The key idea to grasp is that the styling and interactivity of the <svg> can differ depending on its context within the document hierarchy, affecting how it responds to top-level style rules and interactive events like :hover.

I recommend exploring the snippet below to witness these concepts in action:

// JavaScript code to embed SVG content
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;
        }

        .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>
`;

// Generating data URI for the SVG
const dataUri = `data:image/svg+xml;base64,${btoa(someSVG)}`;

// Creating image, background, and iframe elements
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;
// CSS code for styling and animations
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;
}

.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;
                    }

                    .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 inherit styling from the top-level document
  • Does not support CSS interactions like :hover
  • Can utilize CSS animations defined within the SVG itself

background-image

<style>
.rule {
    background-image: url(some.svg);
}
</style>
<div class="rule"></div>
  • Does not inherit styling from the top-level document
  • Does not support CSS interactions
  • Can utilize CSS animations defined within the SVG itself

<iframe>

<iframe src="some.svg"></iframe>
  • Does not inherit styling from the top-level document
  • Can support CSS interactions and animations defined within the SVG

Inline <svg>

<svg>...</svg>
  • Receives all style rules from the top-level document
  • Supports CSS interactions and animations defined within the SVG itself

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Bootstrap side navbar not collapsing when clicked on a link

Currently, I'm working on creating a website for a friend. While I used to have some experience with coding in the past, it has been a while and I am a bit rusty. This time around, I decided to use bootstrap for the project. However, I'm struggli ...

The html viewport size is altered by the mobile keyboard

One issue that arises when using percentage or viewport unit width and height for the <body> element is that the size of these elements will change when a mobile keyboard is invoked due to an input. I have extensively researched this problem without ...

Oops! Looks like we have encountered an issue with reading the property 'checked' of nothing

Whenever I click the checkbox, an image should be displayed. Unfortunately, I encountered an error: Uncaught TypeError: Cannot read property 'checked' of null at (index):185 at dispatch (VM576 jquery.min.js:3) at i (VM5 ...

Does the color of the item change as it gets older?

How can I smoothly transition a color as it ages using a dynamic time scale? I want to calculate the age based on the difference in time rather than triggering an animation after an event. I aim for a seamless gradient transition between two colors over a ...

Achieving Center Alignment for Material-UI's <Table> within a <div> using ReactJS

Currently, I am working with a Material-UI's <Table> embedded within a <div>. My goal is to center the <Table> while maintaining a fixed width. I want the table to remain centered in the browser, but if the browser window is minimize ...

Make sure the division remains fixed even when the window is resized

Having a fixed position and bottom set to 0, I want my div to display at the bottom of the window. The issue arises when the window is resized, causing the div to move up and into other elements. For instance, when opening the console box in Chrome, the f ...

BS4 Dynamic Countdown Clock

I have successfully integrated a countdown timer into my website, utilizing the following HTML code: <div id="clockdiv"> <div> <span class="days"></span> <div class="smalltext">Days</ ...

Emphasizing buttons that are in a "pressed" or "inactive" state

I've implemented three push buttons in my code using input with type="button", which act as toggle buttons (on/off). In the past, I used images to indicate when a button was pressed or reset, but now I want to achieve this effect using CSS. However, ...

What is the best way to add animation to switch between table rows?

I am looking to add animation effects when table rows appear and disappear. Initially, I attempted using a CSS transition, but it did not work due to the change in the display property. Subsequently, I opted for an animation, which provided the desired o ...

Difficulty arises when collapsed text in Bootstrap clashes with the footer design

Hey there! I'm working on this website using Bootstrap, and I've encountered a problem. When you click the "See Wikipedia" button, the content expands and overlaps the footer in a strange way without changing the page height. I've tried adju ...

Utilizing consistent CSS styles across VueJS components

Currently tackling a VueJS 2 project and facing issues with scoped styling when cleaning up the code. My setup involves 3 components that share similarities, prompting me to utilize mixins for consolidating the code into one file. Each component makes use ...

What value is used as the default for justify content?

MDN states that the default value of justify-content is normal, even though it's not listed in the accepted values. What exactly does a normal value mean? normal This means that items are packed in their default position as if no justify-cont ...

Is it achievable to use PHP to automatically scroll to the bottom of a container?

Is there a way to automatically scroll to the bottom of a div container using PHP code instead of javascript or CSS? While I haven't been able to find a solution using just CSS, I have come across some options utilizing javascript. However, since I a ...

CSS - Resizing Images

I am experiencing an issue with the width of an image on my website. I want it to span 100% of the browser frame, but it is currently limited to only 1000px wide. Please take a look at: The image in question is located at the top of the page. Is there a ...

"Troubleshooting a CSS problem with off-canvas layouts

I've created a page with divs that create a parallax effect on scrolling, you can view the demo here. However, I encountered an issue when adding a Foundations off-canvas menu - it prevents me from being able to scroll down. How can I resolve this an ...

The class "slick" in <col class="slick"> does not add any styling or effects

My interpretation of the col element is that it can be used to assign a class to all elements in a column of a table. However, I am experiencing difficulties with this approach. While I am able to apply the class to individual td elements, I am looking for ...

Positioning of CSS elements: Distributing and arranging 4 divs evenly within a single parent div

Is there a more efficient method? div { border: 2px solid black; } #main { width: 107px; height: 107px; padding: 0; text-align: center; font-size: 10px; } #tl, #tr, #bl, #br { position: relative; width: 45px; height: 45px; } #tl { t ...

What is the most effective method for enlarging elements using Javascript?

I have come across many different methods for expanding elements on webpages, such as using divs with javascript and jquery. I am curious to know what the most optimal and user-friendly approach is in terms of performance, among other things. For instance ...

How come the dark grey in CSS appears to be lighter than the standard grey hue?

JSBIN DEMO Could this be a mistake or is it a bug? Shouldn't the dark gray shade be darker than the default grey one? HTML <div class="lightgrey">Light Grey</div> <div class="grey">Grey</div> <div class="darkgrey">Dar ...

unable to display picture on puggy

Check out the code snippet below: <!DOCTYPE html> <html lang="en> <head> <meta charset="UTF-8> <title>Home Page</title> </head> <body> <img src="resources/mainlogo.png" style="width:304px;height:2 ...