Image moves on hover when changing filter in chrome
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>
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;}
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>