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

What is the best way to prompt users to submit comments with a popup textarea box?

Within my project, I have incorporated a dropdown list: <div class="dropdown"> <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select subject <span class="caret"></span> </but ...

Steps to troubleshoot a scrollbar problem while applying flexbox in CSS

I'm currently working with a front-end framework that utilizes a flex layout. In my development of an admin page, I have included sections for the sidebar, header, and main. My objective is to ensure that the sidebar and the header + main sections fun ...

Writing and altering content within the <code> element in Chrome is unreliable

Utilizing a WYSIWYG Editor with contenteditable functionality allows users to input "code snippets" using a <code> element. Here is an example: <div contenteditable="true"> <p> This is a paragraph with an <code>inline s ...

The background widths do not stretch to 100%, but rather stop right before reaching the

Experience it live: Adjust your screen width slightly to activate the mobile layout, but ensure that there is still enough room for a horizontal scroll bar. Astonishingly, all my background images stop short of this point. Innovative Fix To prevent the ...

Creating a zebra-striped list using CSS can be done by styling even and odd list items differently

I am facing an issue with Angularjs and the table tag when using group loops. The problem arises in achieving correct zebra striping for the list. How can I solve this to ensure the zebra pattern is applied correctly? <table> <tbody> <tr ...

Hide HTML div on click

Why does the button disappear when I click on it, but the status refreshes? Javascript $( ".refreshstatus" ).click(function(){ $( ".navplayers" ).load('stats.php'); }); CSS .refreshstatus{ font-family:'Noto Sans'; font-w ...

The iPhone display scaling issue is causing difficulty viewing the entire website

Currently experiencing difficulties with a page that lacks sufficient content, resulting in a smaller height. As a result, the iPhone is scaling the page and cutting off the full menu bar (960px wide). I attempted to set a minimum height using a media quer ...

Possible for jQuery autocomplete to reposition the list?

Is it feasible for me to adjust the position of the dropdown list by moving it down 4 pixels? I've experimented with various styles within .ui-autocomplete {}. These include: margin-top: 4px; top: 4px However, these modifications don't appe ...

The arrows are hidden when using the input type number

On my page, I noticed that the input of type=number is missing its arrows and appears like a regular text input. After doing some investigating, I think it might be due to this: https://i.stack.imgur.com/G1BrV.png My browser of choice is Google Chrome. D ...

Tips for adjusting content that is 900px wide to fit properly on a mobile screen while maintaining its original width

https://i.stack.imgur.com/JELN5.png Despite trying various meta tag variations, I am struggling to get this image properly scaled and displayed in React.js. Any suggestions on how to resolve this issue would be greatly appreciated. ...

Fade in elements as the cursor moves, without hovering over a specific element

I'm working on implementing a fade-in effect for content when the mouse moves (similar to Google's homepage), but I'd like to avoid this behavior if the cursor is hovering over a specific div. Here are the basics: $("html").hover(function( ...

Position the float input to the right on the same line as an element

This Angular code contains a challenge where I aim to have text at the start of a column and an input box on the right side of the page, both aligned on the same line. The issue lies in the code which floats the input to the right but disrupts the alignme ...

Displaying an image that spans the entire width of the browser

I'm currently working on a WordPress site and have encountered an issue with the header image. I want it to span the full width of any browser window. The existing code in the parent theme is as follows: background: url("/test/wp-content/themes/Howt ...

Is there a way to update the button's value upon clicking it?

I've hit a roadblock in my tic tac toe game project during class, and I've been struggling for the past two days to get the X's and O's to show up. The deadline for this assignment is tomorrow! Here are the task requirements: COMPSCI20 ...

Colorful radial spinner bar

I am interested in replicating the effect seen in this video: My goal is to create a spinner with text in the center that changes color, and when the color bar reaches 100%, trigger a specific event. I believe using a plugin would make this task simpler, ...

Stylized widget for showcasing a list of cities for meetups

After extensive searching, I have yet to find a solution to stylize the "City List" widget for Meetup. The specific widget I am focusing on is the first one listed here. () Despite exploring various options such as the widget foundry and conducting onlin ...

Troubleshooting the Missing Border Issue in Tailwind Form Fieldset [Code Snippet Included]

I am developing a basic react application with the help of Tailwind css. Scenario 1: Functioning correctly without tailwind: https://codesandbox.io/s/bold-agnesi-y70ue In this example, the tailwind library is not utilized. The simple react app displays ...

What is the method of generating an HTML tag solely using CSS?

Looking to style HTML tags without altering them in any way? Consider this example: <div id="Code_G" class="editor-group"> editor-group<br /> <div id="Code_L" class="editor-label "> editor-label </div> < ...

Verify that the text entered in the form is accurate, and if it meets the required criteria, proceed to the next

Is it possible to achieve this without using JavaScript? If not, I'd like to find the simplest solution. I have a form that functions similar to a password entry field, and I would like to redirect users to a certain page if they type in a specific p ...

Position the image slider uniformly at the bottom using CSS (utilizing the Slick Carousel library)

I am utilizing the slick carousel library to create a unique and elegant slider. However, when using images with varying heights, I am encountering issues in aligning the images at the same bottom: https://i.stack.imgur.com/ab5s3.png Here is my code snip ...