Reputation: 268293
I have a composited div (it has translate3d
) with an opacity
transition:
#bad {
background-color: red;
-webkit-transition: opacity .5s linear;
-webkit-transform: translate3d(0, 0, 0);
}
If I change its opacity
while transition is undergoing, it will flicker in Safari.
The flicker happens about once in three seconds and is akin to a white flash.
There is no such problem in Chrome.
Scroll up and down in this fiddle to see what I mean.
The problem does not seem to be limited to opacity—changing -webkit-transform
while its transition is undergoing has a similar effect: once in a while the element is rendered in one of the transition's final states.
The problem goes away if I remove -webkit-transform
but unfortunately that's not an option right now.
Can I fix this in Safari by some other means?
Upvotes: 7
Views: 8103
Reputation: 21
The following CSS fix the transition flicker on safari
* {
-webkit-backface-visibility: hidden;
}
Upvotes: 1
Reputation: 1449
In my case I found 3 actions that solved the same problem:
I needed to fade in an image on the ready event, tried with the jQuery animation but the image was flickering on OSX Safari.
Solved with these actions:
1) Analyze the CSS and delete all transition rules applied on the image, they seem to conflict with the animation command.
I had this rule
img {
/*DON'T COPY !!!*/
-webkit-transition:all 0.2s ease-in-out;
-moz-transition:all 0.2s ease-in-out;
-ms-transition:all 0.2s ease-in-out;
-o-transition:all 0.2s ease-in-out;
transition:all 0.2s ease-in-out;
/*DON'T COPY !!!*/
}
I deleted it.
2) Add this CSS rules to the element you need to fade in:
display: none;/*initial state modified by the fadeIn function*/
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-font-smoothing: antialiased;
-webkit-transform-style: preserve-3d;
-webkit-transform: translateZ(0);
3) Use the jQuery function "fadeIn" and don't use the command ".animate({opacity: 1} ecc..".
These actions resolved the flickering problem on OSX Safari .
Upvotes: 3
Reputation: 96
The problem is changing property values and adding animations need to happen at the same time.
A race condition not present in OSX 10.5 was introduced when Core Animation was rewritten in C++. I learned this when my experiments with additive animation developed the same flicker. I found the workaround to be Core Animation's kCAFillModeBackwards. I also found the same workaround was effective for CSS Transitions by hacking up my own fork of WebKit, with emphasis on the hacking part. But conjecture doesn't help WebKit devs and I didn't want to annoy them any further. I do think the problem is with Core Animation, not WebKit. I'm guessing that they should use the same CFTimeInterval derived from a single call to CACurrentMediaTime throughout any given CATransaction.
Unlike transitions, CSS animations do allow for fill modes. It might be difficult to reproduce transition behavior, but that is one option. In particular, the challenge would be replacing interrupted animations with new ones that begin where the previous left off. In other words, it's easy to animate from opacity of 0 to 1 or 1 to 0, but what happens if the user wants to start when current animated progress is at 0.577564? This might require manually modifying the @keyframes style rule, not an easy task.
Then there is the question of the appropriate animation-fill-mode. Normally you wouldn't want to perform layout using forward filling animations, you'd use the CSS properties themselves. But in this case it might be simple enough to not set the underlying value, instead use only a forward filling CSS animation that gets replaced but never removed when finished. The alternative is setting the underlying value via element.style and at the same time adding a backwards filling CSS animation.
Of course, the flicker also does not happen if WebKit doesn't use Core Animation. By far the easiest way to prevent the flicker in your case is to not enable hardware acceleration.
Instead of:
-webkit-transform: translate3d(100px, 100px, 0);
try:
-webkit-transform: translate(100px, 100px);
Upvotes: 8
Reputation: 268293
This seems like a bug in CoreAnimation.
Kevin Doughty blogged about it and provided a simple fiddle to reproduce it.
I am not certain, but I believe it is caused by a Core Animation bug rdar://problem/12081774 a.k.a. the flash of un-animated content.
[...]
I believe the Safari transition flicker is directly related to the bug I filed. The workaround is to use a Core Animation
fillMode
ofkCAFillModeBackwards
orkCAFillModeBoth
. It seems like there is something wrong with animation timing, where a property value change and an animation started on that property within the same transaction don’t actually begin at the same time. A backwards fill solves this by extending the effect of the late starting animation to be applied before its actual start time.
Kevin also reported this as #115278 in WebKit and tried to tackle it but from my understanding he didn't proceed with this and the patch wasn't accepted.
Of course it's not a real answer (doesn't solve the problem) but at least it explains the problem.
Upvotes: 2