Skip to content

Commit

Permalink
fix($animate): ensure keyframe animations are blocked around the reflow
Browse files Browse the repository at this point in the history
Keyframe animations trigger on the first CSS class and not the second.
This may cause a slight flicker during a stagger animation since the
animation has already started before the stagger delay is considered.
This fix ensures that the animation is blocked until the active animation
starts which allows for staggering animations to take over properly.

Closes angular#5018
  • Loading branch information
matsko authored and jamesdaily committed Jan 27, 2014
1 parent 9e2cee2 commit deb2559
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,8 @@ angular.module('ngAnimate', ['ng'])
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
blockTransitions(element);
} else {
blockKeyframeAnimations(element);
}

forEach(className.split(' '), function(klass, i) {
Expand All @@ -1025,13 +1027,21 @@ angular.module('ngAnimate', ['ng'])
element[0].style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
}

function blockKeyframeAnimations(element) {
element[0].style[ANIMATION_PROP] = 'none 0s';
}

function unblockTransitions(element) {
var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY;
if(node.style[prop] && node.style[prop].length > 0) {
node.style[prop] = '';
}
}

function unblockKeyframeAnimations(element) {
element[0].style[ANIMATION_PROP] = '';
}

function animateRun(element, className, activeAnimationComplete) {
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
if(!element.hasClass(className) || !data) {
Expand Down Expand Up @@ -1059,6 +1069,8 @@ angular.module('ngAnimate', ['ng'])
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
}
} else {
unblockKeyframeAnimations(element);
}

if(ii > 0) {
Expand Down
25 changes: 25 additions & 0 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2696,4 +2696,29 @@ describe("ngAnimate", function() {
expect(capturedProperty).not.toBe('none');
}));

it('should block and unblock keyframe animations around the reflow operation',
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {

if (!$sniffer.animations) return;

$animate.enabled(true);

ss.addRule('.cross-animation', '-webkit-animation:1s my_animation;' +
'animation:1s my_animation;');

var element = $compile('<div class="cross-animation"></div>')($rootScope);
$rootElement.append(element);
jqLite($document[0].body).append($rootElement);

var node = element[0];
var animationKey = $sniffer.vendorPrefix == 'Webkit' ? 'WebkitAnimation' : 'animation';

$animate.addClass(element, 'trigger-class');

expect(node.style[animationKey]).toContain('none');

$timeout.flush();

expect(node.style[animationKey]).not.toContain('none');
}));
});

0 comments on commit deb2559

Please sign in to comment.