angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.85k stars 27.52k forks source link

$animateCss not working correctly webkit browsers. #11984

Closed BirdInTheCity closed 9 years ago

BirdInTheCity commented 9 years ago

I followed the $animateCss documentation to build an accordion-style component with dynamic height. The animation works fine in Chrome, but displays oddly in webkit-based desktop/mobile browsers.

The issue seems to be caused by removing the height property after the animation completes: parent[0].style.removeProperty('height'). With this line omitted, the animation works correctly.

Animated gif of the glitch as seen in iOS Codepen Example

.animation('.itin-item-open', ['$animateCss', function($animateCss) {
        return {

            enter: function(element, doneFn) {
                var parent = element.parent();
                openHeight = element[0].offsetHeight + 20 + 'px';

                var animateParent = $animateCss(parent, {
                    from: {height: closedHeight},
                    to: {height: openHeight },
                    addClass: 'md-whiteframe-z5 open'
                });
                if (!animateParent) {
                    return doneFn();
                }
                animateParent.start().done(function(){
                    parent[0].style.removeProperty('height');
                    doneFn();
                });
            },

            leave: function(element, doneFn) {
                var parent = element.parent();
                openHeight = element[0].offsetHeight + 'px';
                element.css('opacity', '0');

                var animateParent = $animateCss(element.parent(), {
                    from: {height: openHeight},
                    to: {height: closedHeight},
                    removeClass: 'md-whiteframe-z5 open'
                });
                if (!animateParent) {
                    return doneFn();
                }

                animateParent.start().done(function(){
                    parent[0].style.removeProperty('height');
                    doneFn();
                });

            }
        };
    }])
posixpascal commented 9 years ago

This is not only an iOS issue but rather a webkit issue. I can reproduce this in Safari V8.0.6 (10600.6.3).

BirdInTheCity commented 9 years ago

@posixpascal You're correct. I've updated the post accordingly.

matsko commented 9 years ago

@BirdInTheCity I'm looking into it.

Note that:

                if (!animateParent) {
                    return doneFn();
                }

Is not needed anymore with 1.4.0 final. You can also do this to avoid using the doneFn.

                var animator = $animateCss(element.parent(), {
                    from: {height: openHeight},
                    to: {height: closedHeight},
                    removeClass: 'md-whiteframe-z5 open'
                }).start();
                animator.done(function(){
                    parent[0].style.removeProperty('height');
                });
                return animator;

I'll also work on making done() chainable once the webkit issue is fixed.

matsko commented 9 years ago

So the problem here is that you have a CSS class called .animated which sits on the element being animated. This in turn causes the element to always animate any style changes so long as the transition property is present on the element. The fact that chrome or firefox do not animate the trailing removal of the height CSS style are irrelevant since transitions should always animate any style changes.

That being said, managing the .animated CSS class and the removal of the height property are out of context in terms of $animateCss so there's nothing it can do here.

The solution for you is to apply the .animated CSS class as the event of the animation:

                var animator = $animateCss(element.parent(), {
                    event: 'animated',
                    from: {height: openHeight},
                    to: {height: closedHeight},
                    removeClass: 'md-whiteframe-z5 open'
                }).start();

And remove it from the element all together. This way the CSS class will be temporarily applied to the element for the duration of the animation.