Preventing SVG filters from disappearing during hover with smooth transitions

Exploring new concepts, I have delved into the fascinating world of SVG objects. I recently designed a button with a filter applied to it. However, the designer I am collaborating with has requested a hover effect where the filter (a drop shadow) transitions from opacity 1 to 0 on hover, and then back to 1 when not hovered over.

Although I attempted to implement a smooth transition using traditional methods, the result fell short of expectations.

Below is the code I am working with:

HTML

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 216 216" style="enable-background:new 0 0 216 216;" xml:space="preserve">
  <filter id="fade" height="150%" width='150%'>
     <feMerge>
      <feMergeNode/>
      <!-- this contains the offset blurred image -->
      <feMergeNode in="SourceGraphic" />
      <!-- this contains the element that the filter is applied to -->
    </feMerge>
  </filter>
  <filter id="dropshadow" height="150%" width='150%'>
    <feGaussianBlur in="SourceAlpha" stdDeviation="25" />
    <!-- stdDeviation is how much to blur -->
    <feOffset dx="0" dy="15vh" result="offsetblur" />
    <!-- how much to offset -->
    <feComponentTransfer>
      <feFuncA type="linear" slope="0.4" />
    </feComponentTransfer>
    <feMerge>
      <feMergeNode/>
      <!-- this contains the offset blurred image -->
      <feMergeNode in="SourceGraphic" />
      <!-- this contains the element that the filter is applied to -->
    </feMerge>
  </filter>
  <a href='' id='playvideo_button'>
    <g>
      <path class="st0" d="M108,24c-46.4,0-84,37.6-84,84s37.6,84,84,84s84-37.6,84-84S154.4,24,108,24z" />
      <polygon class="st1" points="92,140 92,76 140,108" />
    </g>
  </a>
</svg>

CSS

svg {
  width: 30vw;
  height: 30vh;
  cursor: pointer;

}

svg .st0 {
  fill: #4982CF;
  transition: filter.6s ease-out;
  filter: url(#dropshadow);
}
svg .st1 {
  fill: #ffffff;

}
svg:hover .st0{
  filter: url(#fade);
}

For further experimentation, here is a Fiddle that I have been working with.

Edits

To address the issue, I attempted creating a second filter involving a transparent overlay. Unfortunately, this also resulted in a less than ideal transition effect. Undoubtedly, I find myself uncertain about the next steps to take in resolving this challenge.

Answer №1

If you're looking to create a shadow effect using SVG filters, there is a more elegant approach than simply applying transitions to the filter itself. Here are some key points to consider:

  • It's important to properly size both the SVG and the filter regions to ensure the shadow is displayed correctly without being cut off.
  • Remember that you cannot transition filters directly.
  • When using CSS units within an SVG filter, it's best to stick to objectBoundingBox (%) or userSpaceOnUse (viewbox) units for better compatibility.
  • Take note of how the filter is structured to allow it to appear above the shape without obscuring it. The "operator="out" part of the filter is key for this.
  • Always enclose your filter in a defs element, as some browsers may require this for proper rendering.
  • Avoid using Illustrator exports as templates for SVG code, as they are often not well-constructed for SVG purposes.

Overall, trying to decode or modify Illustrator export code is not the most effective way to learn SVG. It can lead to frustration and confusion rather than learning and understanding. Here's a cleaner approach to creating a shadow effect in SVG:

svg {
  width: 30vw;
  height: 30vh;
  cursor: pointer;
}

svg .st0 {
  fill: #4982CF;
}

svg .st1 {
  fill: #ffffff;
}

#usedshadow {
   opacity: 1;
   transition: opacity 0.6s;
}

#usedshadow:hover {
   opacity: 0;
   transition: opacity 0.6s;
}
<svg version="1.1" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300">

  <defs>
    <filter id="dropshadow" x="-50%" y="-50%" height="200%" width='200%'>
      <feGaussianBlur in="SourceAlpha" stdDeviation="10" />
      <!-- stdDeviation is how much to blur -->
      <feOffset dx="0" dy="15" result="offsetblur" />
      <!-- how much to offset -->
      <feComponentTransfer>
        <feFuncA type="linear" slope="0.4" />
      </feComponentTransfer>
      <feComposite operator="out" in2="SourceGraphic"/>
    </filter>

    <g id="myshape">
      <path class="st0" d="M108,24c-46.4,0-84,37.6-84,84s37.6,84,84,84s84-37.6,84-84S154.4,24,108,24z" />
      <polygon class="st1" points="92,140 92,76 140,108" />
    <g>

  </defs>

  <use xlink:href="#myshape"/>
  <use id="usedshadow" filter="url(#dropshadow)" xlink:href="#myshape"/>

</svg>

Answer №2

To create the illusion of a drop shadow, consider using a path with a gaussian blur instead of a filter. Here is the outcome I achieved:

https://i.sstatic.net/ZwmUg.png

By directly manipulating the "drop shadow" in this manner, you can easily apply a CSS transition for opacity.

svg #shadow{
  transition: all 0.65s;
  opacity:1;
}
svg:hover #shadow{
  opacity:0;
}

Below is the full SVG code:

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   width="216"
   height="216"
   id="svg3013">
  <defs
     id="defs3015">
    <filter
       x="-0.14227594"
       y="-0.13746469"
       width="1.2845519"
       height="1.2749294"
       color-interpolation-filters="sRGB"
       id="filter3826">
      <feGaussianBlur
         id="feGaussianBlur3828"
         stdDeviation="8.4688065" />
    </filter>
  </defs>
  <g
     transform="translate(0,-836.36218)"
     id="layer1">
    <path
       d="m 183.57143,107.07143 a 71.428574,73.928574 0 1 1 -142.857143,0 71.428574,73.928574 0 1 1 142.857143,0 z"
       transform="matrix(1.064,0,0,1.0280193,-11.320001,836.29069)"
       id="shadow"
       style="fill:#1a1a1a;fill-opacity:1;stroke:none;filter:url(#filter3826)" />
    <g
       transform="translate(-0.14285916,0.7142867)"
       id="g3806">
      <path
         d="m 183.57143,107.07143 a 71.428574,73.928574 0 1 1 -142.857143,0 71.428574,73.928574 0 1 1 142.857143,0 z"
         transform="matrix(1.064,0,0,1.0280193,-11.177142,835.5764)"
         id="path3021"
         style="fill:#4982cf;fill-opacity:1;stroke:none" />
      <path
         d="m 86.476396,914.53271 0,58.81194 54.094674,-27.18845 z"
         id="path3796"
         style="fill:#ffffff;stroke:none" />
    </g>
  </g>
</svg>

For a live demonstration, visit: https://jsfiddle.net/h3s1hp3k/

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

${resource} and ${promise} are both returning undefined values

Encountering the following error: TypeError: Cannot call method 'then' of undefined while working with the code below: App.controller('MainCtrl', ['$scope', 'Main', 'MainFilter', function($scope, Main, M ...

Utilizing AngularJS to create a dynamic autocomplete feature with data sourced

I'm currently implementing an autocomplete feature using the REST Countries web service. The goal is to provide suggestions as the user starts typing in an input field, and once a country is selected, display information about it. I am considering usi ...

How can I successfully transfer all user information when the edit button is clicked?

A new display page has been developed using php to show all user records in a table. The page includes delete and edit buttons for managing users. While the delete option is working fine, there is an issue with getting the edit button to function correctly ...

Incrementing values in ng-repeat object automatically

My project involves extracting game information from mlb.com and utilizing angularjs along with the ng-repeat directive to display it. A sample of the JSON feed is shown below. { "data": { "games": { "next_day_date": "2017-08-19", "mo ...

Store the information in the user interface of React by converting it into a file format

Currently, I am retrieving data from an API and downloading a specific file. My goal is to store this same file in the public directory within my react application. https://i.sstatic.net/bS8Z4.png this.state = { fileDownloadUrl: null, fileName ...

Tips for incorporating a CSS transition when closing a details tag:

After reviewing these two questions: How To Add CSS3 Transition With HTML5 details/summary tag reveal? How to make <'details'> drop down on mouse hover Here's a new question for you! Issue I am trying to create an animation when t ...

Modify a value using jQuery

On my Asp.net webform, I have a label called "LabelTotalNumber". I am looking to update the value of this label every minute using jQuery without having to refresh the form. How can I achieve this? Currently, I am able to accomplish updating the value onc ...

Guide on accessing CGI Script response using AJAX

Greetings, Here is the situation: I'm working on a login form. Once the submit button is clicked, it needs to trigger a CGI script called "someurl?userName=user&password=pwd". Depending on the response from the script, I should be able to navigat ...

The page background appears to be incomplete in its coloring

As I work on creating a web application for personal use, my goal is to ensure it is mobile-friendly. However, I've encountered an issue where the background of my language page isn't displaying in full blue color as intended. Despite trying diff ...

Using jQuery for scripting

I had this code working perfectly five minutes ago, but after restarting my app it just stopped. I'm not sure whyyyyyy: <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script> $( ...

Changing JSON into an array with typescript

I have encountered a JSON structure that is causing me some trouble: const help = [ { "en": [ { "test2": [ { "title": "Naslov1", &quo ...

Leverage promises to alter reactive data, strategically placing them to minimize the frequency of triggers being activated

Initial Method const list = reactive([1, 2, 3, 4, 5]); const clickHandler = () =>{ list.push(...[11, 12, 13, 14, 15]); list.push(...[16, 17, 18, 19, 20]); Promise.resolve().then(() => { list.push(33) ...

Two functions are contained within an object: Function A and Function B. Function A calls Function B from within its own code

If I have two functions within an Object. Object = { Function1() { console.log('Function 1') }, Function2() { this.Function1() } } The Function1 is not being executed. Can someone explain why this is happening an ...

How to Overcome Read-only HTML Components in Selenium with Python?

I am working on automating a task using Selenium in Python, and part of it involves selecting a date. The website I am testing has an input box for date selection that displays a standard date table when clicked. Unfortunately, the input text box is read- ...

Utilizing JQuery to extract JSON data from a web service

I'm utilizing a web service to retrieve statistical information. The web service returns the results in JSON format. Below is the jQuery code I am using to fetch data from the web service: $.ajax({ type: "POST", url: webMethod, //data: p ...

Using Regular Expression to verify the presence of numbers and spaces

Currently, I have implemented a regular expression that ensures my string contains 5 digits. While this regex works flawlessly, I now also require it to allow white spaces: both "123 45" and "12345" should meet the criteria. string.match(/^\d{5}$/g); ...

Exploring the functionality of maximizing and minimizing logic in an Angular Bootstrap modal popup

I'm currently utilizing Angular Bootstrap Modal Popup and I'd like to include options for Maximize and Minimize in addition to the close button. By clicking on the maximize option, the popup should expand to full screen, and by clicking on minimi ...

Using destructuring assignment in a while loop is not functional

[a,b] = [b, a+b] is ineffective here as a and b are always set to 0 and 1. However, using a temporary variable to swap the values does work. function fibonacciSequence() { let [a, b, arr] = [0, 1, []] while (a <= 255) { arr.concat(a) [a, ...

How to send form group in Angular when the enter key is pressed

When I press the submit button on a form, it sends a request to the database to filter data in a grid. However, I also want the form to submit when the enter key is pressed. HTML <form [formGroup]="bmForm" (keyup.enter)="onSearchClic ...

ASP.NET ensures that the entire page is validated by the form

Is it possible to validate only a specific part of the form instead of the entire page? Currently, when I try to validate textboxes on the page, the validation is applied to all textboxes. Here are more details: https://i.stack.imgur.com/eowMh.png The c ...