angular.js icon indicating copy to clipboard operation
angular.js copied to clipboard

Safari - ng-animate using ng-class value is not animating on ng-enter

Open chrissfa opened this issue 9 years ago • 26 comments

Possibly related to recently fixed and closed issue #12376. I am finding ng-animate never works upon ng-enter / ng-enter-active in Safari if relying on a ng-class value. Works fine in other browsers.

For instance, if i use ng-class="my-value" and my-value is set to 'right-to-left', the ng-enter animation will try and trigger (I can see this occurring in element inspector - it sits there for length of animation set in CSS) but no animation is seen in browser. If I manually add 'right-to-left' as a normal class in mark-up, the animation works perfectly.

Noticing that while trying to animate Safari has some extra classes over Chrome, such as: 'right-to-left-add-active', 'enter-active', right-to-left-add.

I will try an provide a JSFiddle over the next few days.

chrissfa avatar Aug 05 '15 22:08 chrissfa

Actually, just forked the Plunker that was working from #12376.

http://plnkr.co/edit/40JgZnOHnxxeOKvgvw1F?p=preview

Added myValue='left-ani' to ng-click, and forced css animations to rely on this class. Press next and ng-enter doesn't work first time in Safari, while it will always work in Chrome.

chrissfa avatar Aug 05 '15 22:08 chrissfa

Looking into it.

matsko avatar Aug 06 '15 05:08 matsko

FWIW - the Plunker for both this and #12376 is still problematic for me in Safari 7.1.7, and more importantly my iOS devices and emulators

olore avatar Aug 31 '15 12:08 olore

Does anyone have a solution for that problem ? ng-enter combined with 3d animations is not reliable on safari (tested on 6,7 and 8) nor iOS safari (tested on 8). Is anybody has a workaround ?

raffaelcavaliere avatar Sep 15 '15 01:09 raffaelcavaliere

Heh. Seeing this issue as well but with ng-if. Works OK on Chrome, but not Safari 8 or iOS 9 Safari. Here's some sample code.

.tn-footer-bar.ng-enter, .tn-footer-bar.ng-leave { -webkit-transition: 0.3s ease-in-out; }

.tn-footer-bar.ng-enter, .tn-footer-bar.ng-leave.ng-leave-active { -webkit-transform: translate3d(0, 100%, 0); }

.tn-footer-bar.ng-leave, .tn-footer-bar.ng-enter.ng-enter-active { -webkit-transform: translate3d(0, 0, 0); }

degamer106 avatar Sep 28 '15 02:09 degamer106

Today I have already seen similar issue myself. I tested on Mac Safari 9.0, it works just fine. But on IOS Safari 9.0 (iphone 6 or simulator), it doesn't work.

oliverzy avatar Oct 13 '15 15:10 oliverzy

I've been having the same issue of inconsistent application of animations in Safari in iOS for some time as well. Tested with iOS 8.x & 9.0.1.

anishbenji avatar Oct 19 '15 12:10 anishbenji

I can confirm that this issue is present in Safari 9.0.1 running on OSX 10.10.5 and Safari 9.0.2 on OSX 10.11.2. The browser seems to completely ignore the enter transition in the older version, whereas the leave transition works as expected. In the newer version the enter transition works sometimes, however it is completely unreliable.

What is also interesting, the animation seems to work fine with version 1.3 of angular (see codepen for version 1.3.14), but fails to work on version 1.4 (see codepen for version 1.4.8) and the 1.5 beta (see codepen for 1.5.0-beta.2).

kazimierasc avatar Nov 25 '15 10:11 kazimierasc

@matsko I wonder if that has something to do with the spacing of child animations with requestAnimationFrame

Narretz avatar Nov 26 '15 12:11 Narretz

Confirming the issue is still present in 1.4.9

jamesmfriedman avatar Jan 25 '16 19:01 jamesmfriedman

Note: it looks like the animation blocking in Safari is broken when the structural animation has a parent class-based animation. Basically, the transition in the ng-enter class is executed, even though it should be blocked (by setting a negative transition delay). In other words: ng-enter should set opacity to 0 immediately, but because the blocking is not working Safari tries to transition it to 0 from 1, which means when the actual animation kicks in shorty afterwards, it will try to transition from a value such as opacitay: 0.9999 to 1, which doesn't do anything visually. Obviously a pretty big bug, but I don't know if it can be fixed with the current ngAnimate architecture.

http://plnkr.co/edit/Kyb3MHV1SG93fG1BKFZm?p=preview

Narretz avatar Feb 17 '16 18:02 Narretz

From mobile safari's docs on transition-delay. It very humorously states what the desired behavior is for negative values, followed by the fact that negative values are invalid.

If the value is negative, the transition executes the moment the property changes but appears to begin at the specified negative offset—that is, begins part-way through the transition. Nonzero values must specify a unit: s for seconds, ms for milliseconds. Negative values are invalid.

https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariCSSRef/Articles/StandardCSSProperties.html#//apple_ref/doc/uid/TP30001266-SW11

jamesmfriedman avatar Feb 17 '16 18:02 jamesmfriedman

Are you sure it's humorous. It's just not making sense (imo). It describes what should indeed happen with negative values and then it says they are invalid :confused:

gkalpak avatar Feb 17 '16 19:02 gkalpak

This explains why Safari doesn't render structural animations properly sometimes. Thank you @jamesmfriedman for pointing this out. We'll make a fix that reverts to the older method of blocking for Safari.

matsko avatar Feb 17 '16 20:02 matsko

So Safari does indeed support negative delays, but the rendering code for it doesn't pick it up fast enough within one requestAnimationFrame. The real fix for this is to wait two frames (this is what we do in the current implementation of Animate in Angular2: https://github.com/angular/angular/blob/master/modules/angular2/src/animate/animation.ts#L59).

I have tested the code in plunkr with the double RAF and it seems to be working: http://plnkr.co/edit/ffc7Eog9RrsV5pvLojY2?p=preview

matsko avatar Feb 17 '16 20:02 matsko

@matsko Looks good on my OSX Safari 8.08.

On iOS 9.2.1, when pressing "Next" the content slides off the screen to the left as expected, but the new content simply appears in its place. It does not slide in from the right as expected.

olore avatar Mar 01 '16 14:03 olore

DevTips I some cases, animation may be fixed using ng-enter-prepare and ng-leave-prepare (added in 1.4.10/1.5.0)

wszerad avatar Mar 18 '16 15:03 wszerad

I was able to make Safari behave nicely by adding a delay to the animation and making sure that the element that was sliding in, was hidden behind the element sliding out. Extend the delay and animation time to 10s and check it works then speed it up again. But leave a small delay e.g. animation-delay: 0.05s;

Something like this: (when using https://github.com/troch/angular-multi-step-form)

.sliding-steps {
  main {
    min-height: 100vh;
    position: relative;
    overflow: hidden;
    width: 100%;
  }

  .form-step {
    background-color: $white;
    position: absolute;
    z-index: 10;
  }

  .ng-enter,
  .ng-leave {
    animation-duration: 0.2s;
    animation-timing-function: ease-in-out;
    animation-delay: 0.05s;
  }
  .step-forward {
    .ng-enter {
      animation-name: slideInRight;
      z-index: 1;
    }

    .ng-leave {
      animation-name: slideInLeft;
      animation-direction: reverse;
      z-index: 9999;
    }
  }

  .step-backward {
    .ng-enter {
      animation-name: slideInLeft;
      z-index: 1;
    }

    .ng-leave {
      animation-name: slideInRight;
      animation-direction: reverse;
      z-index: 9999;
    }
  }

jpduckwo avatar May 18 '16 09:05 jpduckwo

@jpduckwo's workaround works, but if you are using a UIWebView remember to add the webkit prefixes!

dardosordi avatar Jul 08 '16 19:07 dardosordi

@wszerad's tip with ng-enter-prepare (I've added it to the ng-enter rule) worked for me!

.wrapper{
    display: block;
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    will-change: transform;
    perspective: 1000;
    transform-style: preserve-3d;
    transform: translate3d(0,0,0);
    backface-visibility: hidden;
}
    .wrapper.ng-enter-prepare{ opacity: 0; }

    .wrapper.ng-enter, .wrapper.ng-leave {
        opacity: 1;
        transition: transform cubic-bezier(0.250, 0.460, 0.450, 0.940) .4s;
    }

        .wrapper.ng-enter, .wrapper.ng-enter-prepare{
            transform: translate3d(-100%,0,0);
        }
            .wrapper.back.ng-enter, .wrapper.back.ng-enter-prepare{
                transform: translate3d(100%,0,0);
            }

        .wrapper.ng-leave.ng-leave-active {
            transform: translate3d(-100%,0,0);
        }
            .wrapper.back.ng-leave.ng-leave-active {
                transform: translate3d(100%,0,0);
            }

        .wrapper.ng-leave,
        .wrapper.ng-enter.ng-enter-active {
            transform: translate3d(0,0,0);
        }

helloflow avatar Jul 19 '16 13:07 helloflow

This bug is still causing me dramas. @matsko I tried your patched version of animate and it didn't work on Safari 9.1.3

I've stuck with adding a delay of 0.01s which doesn't really allow time for the flash of extra content but still I don't feel like it's properly solved.

Any other ideas on fixing this properly?

(Using angular 1.5.8)

jpduckwo avatar Sep 08 '16 04:09 jpduckwo

@jpduckwo Have you tried the ng-enter-prepare css rule?

Narretz avatar Sep 09 '16 21:09 Narretz

Are there any updates to this thread? The .ng-enter-prepare did not seem to work for me.

briananderson1222 avatar Sep 16 '16 17:09 briananderson1222

I've been following it for months. Dug into it a few times, but could never seem to track down the exact issue.

ng-enter-prepare will work in some cases, but it doesn't stop the root issue I still experience which is that ng-enter gets removed before the transition is actually complete.

A non Angular workaround is to not use ng-enter and just have an animation that runs once on the element whenever it gets created. The only problem is the animation is non-cancellable / transition-able, so if the element has to leave before the enter animation finishes, its jarring.

jamesmfriedman avatar Sep 16 '16 19:09 jamesmfriedman

I am also having this issue. My ng-enter animations are hit or miss depending on the element when it comes to Safari. Everything works ok in Chrome.

ng-prepare didn't affect the issue.

If I change from translate3d to translateX / Y it works consistently.

Also using @jpduckwo's suggestion of animation-delay: 0.01s; also works but in some cases there is a visible flicker of content.

So +1 on getting this fixed

ragamufin avatar Oct 21 '16 14:10 ragamufin

Ok, finally got this working after months, I came back with a fresh mind and sorted it out. The ng-enter-prepare was the trick I needed (thanks @Narretz). So my recommendation for anyone else having this issue is to:

  1. Set the ng-enter-prepare css to the same as the ng-enter (being the initial state of the animation)
  2. Set the ng-enter-active to the end state of the animation.

In my case it was a transitioning screen animation and my SASS rules are as follows to fix the bug of safari not applying the animation...

.sliding-steps {
  .form-step {
    width: 100%;

    &.ng-animate {
      position: absolute;
      -webkit-transition: transform .5s ease-in-out;
      transition: transform .5s ease-in-out;
    }

    // this bit probably not needed, but might stop flash of unwanted content
    &.ng-enter-prepare {
      opacity: 0;
    }
  }

  .step-forward {
    .form-step {
      &.ng-enter,
      &.ng-enter-prepare {
        transform: translateX(100%);

        &.ng-enter-active {
          transform: translateX(0);
        }
      }

      &.ng-leave {
        transform: translateX(0);

        &.ng-leave-active {
          transform: translateX(-100%);
        }
      }
    }
  }

  .step-backward {
    .form-step {
      &.ng-enter,
      &.ng-enter-prepare {
        transform: translateX(-100%);

        &.ng-enter-active {
          transform: translateX(0);
        }
      }

      &.ng-leave {
        transform: translateX(0);

        &.ng-leave-active {
          transform: translateX(100%);
        }
      }
    }
  }
}

jpduckwo avatar Nov 21 '16 02:11 jpduckwo