Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 6760d7a

Browse files
committed
fix($animate): ensure keyframe animations are blocked around the reflow
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 #5018
1 parent 062fbed commit 6760d7a

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/ngAnimate/animate.js

+12
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,8 @@ angular.module('ngAnimate', ['ng'])
10021002
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
10031003
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
10041004
blockTransitions(element);
1005+
} else {
1006+
blockKeyframeAnimations(element);
10051007
}
10061008

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

1030+
function blockKeyframeAnimations(element) {
1031+
element[0].style[ANIMATION_PROP] = 'none 0s';
1032+
}
1033+
10281034
function unblockTransitions(element) {
10291035
var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY;
10301036
if(node.style[prop] && node.style[prop].length > 0) {
10311037
node.style[prop] = '';
10321038
}
10331039
}
10341040

1041+
function unblockKeyframeAnimations(element) {
1042+
element[0].style[ANIMATION_PROP] = '';
1043+
}
1044+
10351045
function animateRun(element, className, activeAnimationComplete) {
10361046
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
10371047
if(!element.hasClass(className) || !data) {
@@ -1059,6 +1069,8 @@ angular.module('ngAnimate', ['ng'])
10591069
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
10601070
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
10611071
}
1072+
} else {
1073+
unblockKeyframeAnimations(element);
10621074
}
10631075

10641076
if(ii > 0) {

test/ngAnimate/animateSpec.js

+25
Original file line numberDiff line numberDiff line change
@@ -2696,4 +2696,29 @@ describe("ngAnimate", function() {
26962696
expect(capturedProperty).not.toBe('none');
26972697
}));
26982698

2699+
it('should block and unblock keyframe animations around the reflow operation',
2700+
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {
2701+
2702+
if (!$sniffer.animations) return;
2703+
2704+
$animate.enabled(true);
2705+
2706+
ss.addRule('.cross-animation', '-webkit-animation:1s my_animation;' +
2707+
'animation:1s my_animation;');
2708+
2709+
var element = $compile('<div class="cross-animation"></div>')($rootScope);
2710+
$rootElement.append(element);
2711+
jqLite($document[0].body).append($rootElement);
2712+
2713+
var node = element[0];
2714+
var animationKey = $sniffer.vendorPrefix == 'Webkit' ? 'WebkitAnimation' : 'animation';
2715+
2716+
$animate.addClass(element, 'trigger-class');
2717+
2718+
expect(node.style[animationKey]).toContain('none');
2719+
2720+
$timeout.flush();
2721+
2722+
expect(node.style[animationKey]).not.toContain('none');
2723+
}));
26992724
});

0 commit comments

Comments
 (0)