CSS transition effect makes image blurry / moves i

2019-01-01 06:26发布

问题:

When the div is hovered over, a CSS transition effect moves the div.

The problem, as you can see in the example, is that the \'translate\' transition has the horrible side effect of making the image in the div move by 1px down/right (and possibly resize ever so slightly?) so that it appears out of place and out of focus...

The glitch seems to apply the whole time the hover effect is applied, and from a process of trial and error I can safely say only seems to occur when the translate transition moves the div (box shadow and opacity are also applied but make no difference to the error when removed).

2nd EDIT: Actually, problem NOT solved!

In creating a JSFiddle to illustrate the problem I stumbled across an interesting observation. The problem only happens when the page has scrollbars. So the example with just one instance of the div is fine, but once more identical divs are added and the page therefore requires a scrollbar the problem strikes again...

Any ideas?!

回答1:

Have you tried this in CSS?

.yourDivClass {
    /* ... */

    -webkit-backface-visibility: hidden;
    -webkit-transform: translateZ(0) scale(1.0, 1.0);
}

What this does is it makes the division to behave \"more 2D\".

  • Backface is drawn as a default to allow flipping things with rotate and such. There\'s no need to that if you only move left, right, up, down, scale or rotate (counter-)clockwise.
  • Translate Z-axis to always have a zero value.

Edit

Chrome now handles backface-visibility and transform without the -webkit- prefix. I currently don\'t know how this affects other browsers rendering (FF, IE), so use the non-prefixed versions with caution.



回答2:

You need to apply 3d transform to the element, so it will get its own composite layer. For instance:

.element{
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
}

or

.element{
    -webkit-transform: translate3d(0,0,0);
    transform: translate3d(0,0,0);
}

More about layer creation criteria you can read right here: Accelerated Rendering in Chrome


An explanation:

Examples (hover green box):

  • Problem: Transition may cause blink effect on sibling elements (OSx Lion, Chrome 30)
  • Solution: An element on its own composite layer

When you use any transition on your element it cause browser to recalculate styles, then re-layout your content even if transition property is visual (in my examples it is an opacity) and finaly paint an element:

\"screenshot\"

The issue here is re-layout of the content that can make an effect of \"dancing\" or \"blinking\" elements on the page while transition happens. If you will go to settings, check \"Show composite layers\" checkbox and then apply 3d transform to an element, you will see that it gets it\'s own layer which outlined with orange border.

\"screenshot\"

After element gets its own layer, browser just needs to composite layers on transition without re-layout or even paint operations so problem have to be solved:

\"screenshot\"



回答3:

Had the same problem with embeded youtube iframe (Translations were used for centering iframe element). None of the solutions above worked until tried reset css filters and magic happened.

Structure:

<div class=\"translate\">
     <iframe/>
</div>

Style [before]

.translate {
  transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
}

Style [after]

.translate {
  transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
  filter: blur(0);
  -webkit-filter: blur(0);
}


回答4:

I recommended an experimental new attribute CSS I tested on latest browser and it\'s good:

image-rendering: optimizeSpeed;             /*                     */
image-rendering: -moz-crisp-edges;          /* Firefox             */
image-rendering: -o-crisp-edges;            /* Opera               */
image-rendering: -webkit-optimize-contrast; /* Chrome (and Safari) */
image-rendering: optimize-contrast;         /* CSS3 Proposed       */
-ms-interpolation-mode: nearest-neighbor;   /* IE8+                */

With this the browser will know the algorithm for rendering



回答5:

Just found another reason why an element goes blurry when being transformed. I was using transform: translate3d(-5.5px, -18px, 0); to re-position an element once it had been loaded in, however that element became blurry.

I tried all the suggestions above but it turned out that it was due to me using a decimal value for one of the translate values. Whole numbers don\'t cause the blur, and the further away I went from the whole number the worse the blur became.

i.e. 5.5px blurs the element the most, 5.1px the least.

Just thought I\'d chuck this here in case it helps anybody.



回答6:

I cheated problem using transition by steps, not smoothly

transition-timing-function: steps(10, end);

It is not a solving, it is a cheating and can be applied not everywhere.

I can\'t explain it, but it works for me. None of another answers helps me (OSX, Chrome 63, Non-Retina display).

https://jsfiddle.net/tuzae6a9/6/



回答7:

Scaling to double and bringing down to half with zoom worked for me.

transform: scale(2);
zoom: 0.5;


回答8:

Try filter: blur(0);

It worked for me



回答9:

filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration

I was helped by setting the value of transition duration .3s equal transition timing steps .3s



回答10:

I\'ve tried around 10 possibly solutions. Mixed them up and they still didn\'t work correctly. There was always 1px shake at the end.

I find solution by reducing transition time on filter.

This didn\'t work:

.elem {
  filter: blur(0);
  transition: filter 1.2s ease;
}
.elem:hover {
  filter: blur(7px);
}

Solution:

.elem {
  filter: blur(0);
  transition: filter .7s ease;
}
.elem:hover {
  filter: blur(7px);
}

Try this in fiddle:

.blur {
  border: none;
  outline: none;
  width: 100px; height: 100px;
  background: #f0f;
  margin: 30px;
  -webkit-filter: blur(10px);
  transition: all .7s ease-out;
  /* transition: all .2s ease-out; */
}
.blur:hover {
  -webkit-filter: blur(0);
}

.blur2 {
  border: none;
  outline: none;
  width: 100px; height: 100px;
  background: tomato;
  margin: 30px;
  -webkit-filter: blur(10px);
  transition: all .2s ease-out;
}
.blur2:hover {
  -webkit-filter: blur(0);
}
<div class=\"blur\"></div>

<div class=\"blur2\"></div>

I hope this helps someone.



回答11:

For me, now in 2018. The only thing that fixed my problem (a white glitchy-flicker line running through an image on hover) was applying this to my link element holding the image element that has transform: scale(1.05)

a {
   -webkit-backface-visibility: hidden;
   backface-visibility: hidden;
   -webkit-transform: translateZ(0) scale(1.0, 1.0);
   transform: translateZ(0) scale(1.0, 1.0);
   -webkit-filter: blur(0);
   filter: blur(0);
}
a > .imageElement {
   transition: transform 3s ease-in-out;
}


回答12:

Just got the same problem. Try to set position:relative to parent element, that worked for me.