Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add hover style inside SVG file or tag

Tags:

html

css

svg

I have an SVG tag that I want to change the fill color when it's hovered. I have added a style tag inside the SVG tag but it seems that the hover doesn't work while simple stylings work just fine. Here is my SVG tag:

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

I have included this svg to the element::after in both ways of:

  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");
    }
    

but none of them works. Any idea on how to tackle this?

like image 639
Ahmad Karimi Avatar asked Dec 04 '19 06:12

Ahmad Karimi


People also ask

How do I hover in SVG?

The simplest way to add a mouseover effect is to use the :hover pseudo-selector in CSS, as you would with an HTML element. CSS styles can be put in a separate document or inside a <style> tag inside the SVG itself.

Can we add style to SVG?

The SVG <style> element allows style sheets to be embedded directly within SVG content. Note: SVG's style element has the same attributes as the corresponding element in HTML (see HTML's <style> element).

Can I change SVG color on hover?

One way to change SVG colors on hover is to use CSS. You can add CSS to your HTML file or you can use an external CSS file. To add CSS to your HTML file, you will need to use the <style> tag.


2 Answers

When you set it as the content of a pseudo element, your svg is actually a CSS <image>. CSS <image> representing svg documents have the same restrictions as html <img> representing svg:

  • No external resources will get fetched
  • Scripts won't run in the inner document
  • The inner document won't be interactive (i.e no pointer-events)
  • ...

This means that any :hover style in this svg document will be useless.

What you can do however is to set this :hover on the parent .slick-next element and change the content there.

To avoid having to store two svg files on your servers with only the fill that will change, you can use of a hack demonstrated by Lea Verou, which exploits the :target pseudo-class. More info on this here.

You would have to restructure your svg so that you have invisible triggerer elements with [id] attributes, so they can become :target. Then all the logic is made using CSS selectors:

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>

And your CSS:

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

Here is a more complex live-snippet since we have to workaround the fact we can't host third party files from 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>

But you can access the simple version in this plnkr.

like image 50
Kaiido Avatar answered Oct 04 '22 22:10

Kaiido


You can consider the use of filter to change the coloration:

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

Related: SVG image inline in CSS

like image 36
Temani Afif Avatar answered Oct 04 '22 22:10

Temani Afif