19

I have an image, when i blur it on hover, it slightly moves, it's like the image shakes in its position, problem only occurs in chrome ( tested with: chromium 63 linux-x86_64 ),

.item img{
  transition: 250ms all ease-in-out;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.item:hover img{
  filter: blur(2px)
}

I thaught it might be related to this issue, but none of the solutions worked.

image moves on hover

UPDATE :

As @Chase said, this is a chrome bug and the most stable solution is to wait for it to be fixed. but for now, the best solution for this issue is @kosh Very's answer

Amin
  • 1,057
  • 1
  • 9
  • 30

5 Answers5

12

This is a confirmed Chrome bug that popped up in a recent update, and should hopefully get resolved soon.

Here's a reduced test case: https://codepen.io/chasebank/pen/KZgYXK

Here's the Chromium issue marked for triage.

I think the best thing to do for now is nothing. Wait for a proper fix to be implemented. It's never a good idea to hack around an acknowledge browser bug.

We can take some comfort in the fact that the only other people seeing this are Chrome users who recently updated. My first try was asking a Slack channel full of skilled devs, and even they weren't seeing it.

$('#toggleBlur').click(function() {
  $('#content').toggleClass('blur')
})
body {
  padding: 5%;
}

div {
  filter: blur(0px);
}

.blur {
  filter: blur(.1px)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="toggleBlur">Toggle blur</button>

<div id="content">
  <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusantium eum nisi voluptate eaque! Sequi sit nemo iste. Earum accusantium rerum consectetur cumque sequi maiores maxime reiciendis, alias beatae accusamus labore.</p>
  <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptate enim magnam nemo atque, ad placeat ab unde consequatur minima velit, ipsam tempora laudantium molestias sapiente perspiciatis quaerat modi ratione voluptatem?</p>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Deleniti commodi cum sed nemo fugiat non esse ex quos consectetur ipsam alias laboriosam, cumque eaque omnis quae accusamus, repellat dolore modi!</p>
</div>
Chase
  • 1,724
  • 2
  • 18
  • 24
  • I'm still having this bug now, with filter: brightness transform: translate3d(0,0,0) seems to be fixing it, though I don't have a pixel-perfect eye. Should I report it somewhere? – eduardogbg Sep 23 '20 at 01:01
7

I have two solutions for you:

filter:blur(0.2px) hack (don't ask me how it works)

.item img
{
  transition: filter 250ms ease-in-out;
  filter: blur(0.2px); /* the lowest value I could get on my machine: 0.12805650383234025436px */
  image-rendering: -webkit-optimize-contrast; /* just in case quality degrades */
}

.item:hover img
{
  filter: blur(2px);
}

Jokes aside, this is probably caused by floating number optimizations done by the Processing Unit, so by setting blur to .2px I am not animating blur(0px), but instead start from another value and instead of calculating it like this (assume we have linear easing):

frame1: 0, frame2: .1, frame3: .2, frame4: .3, ...

it calculates it like that:

frame1: .2, frame2: .2666, frame3: .3332, ...

So the incremental value has changed and no longer causes that misposition. Of course there's no proper math here (this is especially tricky with easings), but you get the idea.

This also skips the first frame with jiggle as well.



Duplicate blurred image and toggle between them (also the most performant way)

<div class="item">
    <img class="blurred"  src="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" alt="">
    <img class="original" src="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" alt="">
</div>

.item
{
  position: relative;
}

.item img
{
  max-width: 300px;
  transition: opacity 250ms ease-in-out;
  will-change: opacity;
}

.item .original
{
  transition-delay: 0;
}

.item .blurred
{
  position: absolute;
  filter: blur(5px);
  opacity: 0;
  transition-delay: .1s;
}

.item:hover .original
{
  opacity: 0;
  transition-delay: .2s;
}
.item:hover .blurred
{
  opacity: 1;
  transition-delay: .1s;
}
CyberAP
  • 995
  • 1
  • 8
  • 16
4

My two cents:

.item {
  width: 200px;
  height: 150px;
  overflow:hidden;
}

img {
  width: 200px;
  transition:filter .5s;
  
  transform: translate3d(-1px, -1px, 0);
  border:solid 1px transparent;
  border-width:1px 0 0 1px;
}

img:hover {
  filter: blur(5px);
}
<div class="item">
  <img src="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" alt="">
</div>
Kosh
  • 14,657
  • 2
  • 15
  • 31
  • Works perfect thanks, I've reduced the code down even further and it still works. See this pen: https://codepen.io/DEfusion/pen/VQPGvx – DEfusion Feb 09 '18 at 15:31
  • @DEfusion, Thank you for your comment! You're right, `overflow` and `transform` do the trick, but `border` is necessary to compensate the shift of `transform` to be pixel-perfect. Though it may be omitted in some cases. – Kosh Feb 09 '18 at 16:16
2

The only way i found to make this work properly is using a svg filter and animate the filter blur with GSAP.

https://jsfiddle.net/eg5yhu26/4/

var timeline = TweenMax.to("#hue1feGaussianBlur", 5, {
  paused: true,
  attr: {
    "stdDeviation": 5
  },
  onUpdateParams: ["{self}"]
});

$(document).on("mouseenter", ".c-grid__item a", function() {
  timeline.play();
});
$(document).on("mouseleave", ".c-grid__item a", function() {
  timeline.reverse();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.14.2/TweenMax.min.js"></script>
<div class="c-grid">
  <div class="c-grid__item">
    <a href="" title="">
      <svg width="100%" height="100%" viewBox="0 0 538 196" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <defs>Using feColorMatrix for Tint FX</defs>
        <!--<filter id="hue1">
        <feColorMatrix id="hue1feColorMatrix" in="SourceGraphic" type="hueRotate" values="0"/>
 </filter>-->
        <filter id="hue1" x="0" y="0">
          <feGaussianBlur id="hue1feGaussianBlur" in="SourceGraphic" stdDeviation="0" />
        </filter>
        <image xlink:href="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" width="100%" height="100%" filter="url(#hue1)" />
      </svg>
    </a>
  </div>
</div>
1

I did a lot of research and I tried a lot of different ways but nothing seems to fix this glitch. The only way to avoid having this jump is to have the blur effect at the start on the image or remove the transition (as there is no issue without transition and of course this not an option to consider).

So the workaround I have found is to use two different images and have the blur(1px) at the start.

The idea is to have the image with the blur effect hidden by opacity:0 and use the same image as a background to simulate an initial image without blur effect. Then the trick is to make the transition of opacity faster than the transition of the filter so we can see the effect of blur(1px) and then the effect of blur(2px)

.item {
  width: 200px;
  height: 150px;
  background: url(https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg);
  background-size: 100%;
}

img {
  width: 200px;
  display: inline-block;
  transition: 2s filter ease-in-out, 0.1s opacity ease-in-out;
  filter: blur(1px);
  opacity: 0;
}

img:hover {
  opacity: 1;
  filter: blur(2px);
}
<div class="item">
  <img src="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" alt="">
</div>

I assume this trick involve more HTML/CSS and you have to change each image on the site, but you can for example create a jQuery code that will do this for. You simply create a class that you append to any image where you need this effect then you target this class and add the necessary code for the trick.

Here is an example:

$('img.blur').each(function() {
  var url = $(this).attr('src');
  $(this).wrap("<div style='display:inline-block;font-size:0;background-image:url(" + url + ");background-size: 100%;'></div>")
})
.blur {
  transition: 2s filter ease-in-out, 0.1s opacity ease-in-out;
  filter: blur(1px);
  opacity: 0;
}

.blur:hover {
  opacity: 1;
  filter: blur(3px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<img src="https://www.wikihow.com/images/thumb/2/25/Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg/aid8673811-v4-728px-Collect-Bodily-Fluid-Samples-from-a-Cat-Step-16.jpg" width="200" class="blur">

<img src="https://lorempixel.com/300/300/" width="300" class="blur" />

<img src="https://lorempixel.com/400/400/" width="400" class="blur" />
Temani Afif
  • 180,975
  • 14
  • 166
  • 216