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

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

Open
chrissfa opened this issue Aug 5, 2015 · 26 comments
Open

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

chrissfa opened this issue Aug 5, 2015 · 26 comments

Comments

@chrissfa
Copy link

chrissfa commented Aug 5, 2015

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
Copy link
Author

chrissfa commented Aug 5, 2015

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.

@matsko matsko self-assigned this Aug 6, 2015
@matsko
Copy link
Contributor

matsko commented Aug 6, 2015

Looking into it.

@olore
Copy link

olore commented Aug 31, 2015

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

@raffaelcavaliere
Copy link

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 ?

@degamer106
Copy link

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);
}

@oliverzy
Copy link

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.

@anishbenji
Copy link

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.

@kazimierasc
Copy link

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).

@Narretz
Copy link
Contributor

Narretz commented Nov 26, 2015

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

@jamesmfriedman
Copy link

Confirming the issue is still present in 1.4.9

@Narretz Narretz modified the milestones: 1.5.x, 1.5.1 Feb 15, 2016
@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

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

@jamesmfriedman
Copy link

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

@gkalpak
Copy link
Member

gkalpak commented Feb 17, 2016

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 😕

@matsko
Copy link
Contributor

matsko commented Feb 17, 2016

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
Copy link
Contributor

matsko commented Feb 17, 2016

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

@olore
Copy link

olore commented Mar 1, 2016

@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.

@wszerad
Copy link

wszerad commented Mar 18, 2016

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

@jpduckwo
Copy link

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;
    }
  }

@dardosordi
Copy link

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

@helloflow
Copy link

helloflow commented Jul 19, 2016

@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);
        }

@jpduckwo
Copy link

jpduckwo commented Sep 8, 2016

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)

@Narretz
Copy link
Contributor

Narretz commented Sep 9, 2016

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

@briananderson1222
Copy link

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

@jamesmfriedman
Copy link

jamesmfriedman commented Sep 16, 2016

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.

@ragamufin
Copy link

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

@jpduckwo
Copy link

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%);
        }
      }
    }
  }
}

@Narretz Narretz modified the milestones: 1.5.x, 1.6.x Mar 31, 2017
@Narretz Narretz modified the milestones: 1.6.x, 1.7.x Apr 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.