Tate Johnson
Tate Johnson

Reputation: 3950

CSS transition stutters after being applied to element with CSS animation

I'm building an AngularJS application that shows and hides an element by transitioning its opacity. The element is also being rotated by applying a CSS keyframe animation. The problem I'm having is the transition or animation stutters.

When the element has an opacity of 1 and the transition fades it out to 0 then the element appears to go back a few frames. This is better demonstrated in a GIF. You can see it jump back just before the opacity changes.

This is my CSS.

.square {
  width: 100px;
  height: 100px;
  margin: 50px;
  background: black;
}

.appear.ng-hide-add {
   -webkit-transition: opacity 300ms linear;
  opacity: 1;
}

.appear.ng-hide-add.ng-hide-add-active {
  opacity: 0;
}

.appear.ng-hide-remove {
  -webkit-transition: opacity 300ms linear;
  opacity: 0;
}

.appear.ng-hide-remove.ng-hide-remove-active {
  opacity: 1;
}

@-webkit-keyframes rotate {
  from {
    -webkit-transform: rotate(0deg);
  }

  to {
    -webkit-transform: rotate(360deg);
  }
}

.rotate {
  -webkit-animation: rotate 1.5s infinite linear;  
}

This is my HTML.

<div ng-app="app" ng-init="show = true">
  <p>Toggle the opacity of the square. Sometimes the rotation is interrupted when the opacity transitions from 1 to 0.</p>
  <button ng-click="show =!show">Toggle</button>
  <div class="square appear rotate" ng-show="show"></div>
</div>

You can play with the whole thing in this codepen. Hoping someone can point me in the right direction.

Upvotes: 6

Views: 7148

Answers (4)

Henrik N
Henrik N

Reputation: 16274

Here's one more workaround just for the fun of it. Slightly less ugly than the first one I suggested. Change the box background color opacity: http://codepen.io/anon/pen/DpuEh

HTML:

<div ng-app="app" ng-init="show = true">
  <button ng-click="show = !show">Toggle</button>
  <div class="square appear rotate" ng-class="{'hidden': !show}"></div>
</div>

CSS:

.square {
  width: 100px;
  height: 100px;
  margin: 50px;
   -webkit-transition: background 300ms linear;
  background: black;
}

.square.hidden {
  background: rgba(0, 0, 0, 0);
}

I'm using rgba to set the background opacity. Just setting the background to white would also have worked in this simple case.

Upvotes: 2

Henrik N
Henrik N

Reputation: 16274

Ugly workaround that may or may not be suitable, depending on your situation: instead of hiding the element (shows the bug) or a container (also shows the bug), you can fade in a background-colored element on top of it.

HTML:

<div ng-app="app" ng-init="show = false">
  <button ng-click="show =!show">Toggle</button>
  <div class="appear" ng-show="show"></div>
  <div class="square rotate"></div>
</div>

CSS:

.appear {
  background: white;
  width: 200px;
  height: 200px;
  position: absolute;
  top: 30px;
  left: 0;
  z-index: 2;
}

Obviously you might need more sophisticated CSS for a more sophisticated layout, but hopefully you get the idea.

CodePen: http://codepen.io/anon/pen/IwBHj

Upvotes: 1

Alexander O&#39;Mara
Alexander O&#39;Mara

Reputation: 60507

This is evidently a WebKit bug. This is clearly not how the CSS should behave, and it does behave as expected in Firefox if you remove the vendor prefixes. You will notice that the animation resets when an additional animations/transitions are applied. This is similar to a known bug that was recently fixed in which multiple CSS transitions being applied at different times would cause a layout flash. I would recommend reporting the bug to the WebKit team so that it can be fixed.

Upvotes: 1

Rufus
Rufus

Reputation: 2078

I would consider using translate3D on the transform to force hardware acceleration.

    -webkit-transform: translate3d(0,0,0);

This uses hardware acceleration (GPU) for the CSS transitions.

Upvotes: 0

Related Questions