Search code examples
csscss-animationscss-transitions

CSS filter drop-shadow does not provide smooth transition


I have custom image frames (laptop in this case) and I want shadow transition around each on mouseover. Here I use drop-shadow transition, but I'm not able to achieve smooth cross-browser behavior with this solution.

In safari transition doesn't work at all:

enter image description here

In chrome it works much better but still not ideal - you can notice how shadow jumps in the very end of the animation:

enter image description here

How do I fix current solution, or maybe anyone can advice another approaches to achieve same? I can think only about extra shadow image with opacity / scale animation, but that means for each frame I want to add - I will need separate image for shadow layer, so I hope community has better solutions.

UPD: dont forget to add will-change: opacity on top of awesome solution from @Stuart to fix OSX Safari rendering issues

.wrapper {
  position: relative;
  transition: filter .5s;
  display: inline-flex;
}

.content {
  top: 7px;
  bottom: 4px;
  left: 13px;
  right: 13px;
  overflow: hidden;
  position: absolute;
  background: #F4F4F5;
  z-index: 0;
}

img {
  position: relative;
  width: 100%;
  height: 100%;
}

svg {
  position: relative;
  z-index: 1;
}

.wrapper:hover {
  filter: drop-shadow(2px 2px 2px #44444444);
}
<div class="wrapper">
  <div class="content">
    <img src="https://picsum.photos/133/96" />
  </div>
  <svg width="161" height="107" viewBox="0 0 161 107" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path fill-rule="evenodd" clip-rule="evenodd" d="M15.9128 0C11.7771 0 8.42442 3.91065 8.42442 8.73469V99.3571H0.936047C0.419082 99.3571 0 99.846 0 100.449V103.724C0 105.534 1.25725 107 2.80814 107H158.192C159.743 107 161 105.534 161 103.724V100.449C161 99.846 160.581 99.3571 160.064 99.3571H152.576V8.73469C152.576 3.91065 149.223 0 145.087 0H15.9128ZM147.895 100.449V8.73469H13.1047V100.449H65.5233C65.5233 101.655 66.3614 102.633 67.3954 102.633H91.7326C92.7665 102.633 93.6047 101.655 93.6047 100.449H147.895ZM79.0959 6.55102C79.8714 6.55102 80.5 5.81778 80.5 4.91327C80.5 4.00875 79.8714 3.27551 79.0959 3.27551C78.3205 3.27551 77.6919 4.00875 77.6919 4.91327C77.6919 5.81778 78.3205 6.55102 79.0959 6.55102Z" fill="white"/>
    <path fill-rule="evenodd" clip-rule="evenodd" d="M9.36047 100.449H0.936047V103.724C0.936047 104.931 1.77421 105.908 2.80814 105.908H158.192C159.226 105.908 160.064 104.931 160.064 103.724V100.449H151.64V8.73469C151.64 4.51366 148.706 1.09184 145.087 1.09184H15.9128C12.294 1.09184 9.36047 4.51366 9.36047 8.73469V100.449ZM8.42442 8.73469C8.42442 3.91065 11.7771 0 15.9128 0H145.087C149.223 0 152.576 3.91065 152.576 8.73469V99.3571H160.064C160.581 99.3571 161 99.846 161 100.449V103.724C161 105.534 159.743 107 158.192 107H2.80814C1.25725 107 0 105.534 0 103.724V100.449C0 99.846 0.419082 99.3571 0.936047 99.3571H8.42442V8.73469ZM80.5 4.91327C80.5 5.81778 79.8714 6.55102 79.0959 6.55102C78.3205 6.55102 77.6919 5.81778 77.6919 4.91327C77.6919 4.00875 78.3205 3.27551 79.0959 3.27551C79.8714 3.27551 80.5 4.00875 80.5 4.91327Z" fill="#E8E8EA"/>
  </svg>
</div>


Solution

  • If you start off with an initial drop-shadow with the same dimension, but just transparent, you get a much smoother transition, because the drop-shadown already exists:

    .wrapper {
      position: relative;
      transition: filter .5s;
      display: inline-flex;
      filter: drop-shadow(2px 2px 2px transparent);
    }
    
    .content {
      top: 7px;
      bottom: 4px;
      left: 13px;
      right: 13px;
      overflow: hidden;
      position: absolute;
      z-index: 0;
    }
    
    img {
      position: relative;
      width: 100%;
      height: 100%;
    }
    
    svg {
      position: relative;
      z-index: 1;
    }
    
    .wrapper:hover {
      filter: drop-shadow(2px 2px 2px #44444444);
    }
    <div class="wrapper">
      <div class="content">
        <img src="https://picsum.photos/133/96" />
      </div>
      <svg width="161" height="107" viewBox="0 0 161 107" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path fill-rule="evenodd" clip-rule="evenodd" d="M15.9128 0C11.7771 0 8.42442 3.91065 8.42442 8.73469V99.3571H0.936047C0.419082 99.3571 0 99.846 0 100.449V103.724C0 105.534 1.25725 107 2.80814 107H158.192C159.743 107 161 105.534 161 103.724V100.449C161 99.846 160.581 99.3571 160.064 99.3571H152.576V8.73469C152.576 3.91065 149.223 0 145.087 0H15.9128ZM147.895 100.449V8.73469H13.1047V100.449H65.5233C65.5233 101.655 66.3614 102.633 67.3954 102.633H91.7326C92.7665 102.633 93.6047 101.655 93.6047 100.449H147.895ZM79.0959 6.55102C79.8714 6.55102 80.5 5.81778 80.5 4.91327C80.5 4.00875 79.8714 3.27551 79.0959 3.27551C78.3205 3.27551 77.6919 4.00875 77.6919 4.91327C77.6919 5.81778 78.3205 6.55102 79.0959 6.55102Z" fill="white"/>
        <path fill-rule="evenodd" clip-rule="evenodd" d="M9.36047 100.449H0.936047V103.724C0.936047 104.931 1.77421 105.908 2.80814 105.908H158.192C159.226 105.908 160.064 104.931 160.064 103.724V100.449H151.64V8.73469C151.64 4.51366 148.706 1.09184 145.087 1.09184H15.9128C12.294 1.09184 9.36047 4.51366 9.36047 8.73469V100.449ZM8.42442 8.73469C8.42442 3.91065 11.7771 0 15.9128 0H145.087C149.223 0 152.576 3.91065 152.576 8.73469V99.3571H160.064C160.581 99.3571 161 99.846 161 100.449V103.724C161 105.534 159.743 107 158.192 107H2.80814C1.25725 107 0 105.534 0 103.724V100.449C0 99.846 0.419082 99.3571 0.936047 99.3571H8.42442V8.73469ZM80.5 4.91327C80.5 5.81778 79.8714 6.55102 79.0959 6.55102C78.3205 6.55102 77.6919 5.81778 77.6919 4.91327C77.6919 4.00875 78.3205 3.27551 79.0959 3.27551C79.8714 3.27551 80.5 4.00875 80.5 4.91327Z" fill="#E8E8EA"/>
      </svg>
    </div>