Jump to content
Search Community

Animation not playing on mobile safari refresh

martis test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hey guys,

 

I have found an odd issue, not sure if it is Tween, cache, or browser related, BUT....

 

On first load of this page it runs perfectly on iphone/ipad...

 

http://www.thegeminisociety.com/

 

When I RELOAD the page the animation only shows the tail end.

 

I am using this at the bottom of my page to fire off my JS using JQuery....

 

<script>

 

$(document).ready(init());

 

</script>

 

I call my animation function at the end of the chain in init().

 

Does anyone know how I might track this issue down?

 

Works perfectly on desktop browsers, but weirds out on mobile safari. Thanks!

 

UPDATE: I see the animation on reload if I TOUCH the screen after reload. This is really weird!

Link to comment
Share on other sites

Hey Martis,

 

Awesome site you have there. Very cool animation.

 

I tested on my iPhone4S and re-loaded a dozen or so times. I only saw the animation skip once or twice. This seems very reminiscent of what Flash would do when it ran its initial garbage collection routine (processor was bogged down).

 

Also the times that the animation did skip, I did not have to touch the screen to activate the animation, it happened on its own.

 

[EDIT] I must have reloaded 30 times, and I never had the animation not play at all. It always eventually played (after 2 seconds) without touching the screen. Again, this delay only happened rarely.

 

I really think that on load Safari simply has its hands full processing the contents of the page. By the time Safari catches its breath, the first 1-2 seconds of your animation haven't been rendered and TweenLite says "oh snap, 2 seconds have passed, let's make sure the animation begins playing where it should" (which is at the 2 second mark).

 

Perhaps someone else has a better idea of why this happening, but I really think this is a case where mobile devices simply lack the juice of desktops. From what I can tell, TweenLite is doing everything right.

 

I would say run a test and put a .5 to 1 second delay on the animation. See if that makes the issue go away. If so, I would say that a strong case could be made that Safari just isn't ready (even though the document ready event fired) to render the animation when TweenLite starts playing.

Link to comment
Share on other sites

Thanks, glad you like the page!

 

So I found a solution, a very odd one, but a solution.

 

I tried setting more delay on the animations and I had the same results.

 

I then realized if I touched the screen the animations would come on.

 

I finally tried putting a jQuery animation BEFORE my tweens and wa-la it plays the animation EVERYTIME.

 

I am baffled as to why my solution works. Does jQuery.animate somehow force the page to render?

 

Here is my code... the jQuery.animate somehow resolved the issue?

 

function animateAboutUs() {
var sons = $('#sons');
var of = $('#of');
var zeus = $('#zeus');
var introCopy = $('#introCopy');

sons.animate({opacity:1}, 1000);
TweenMax.to(sons, 1, {css:{width:"797px"}, ease:Quad.easeOut, delay:1});
TweenMax.to(of, 1, {css:{width:"386px"}, ease:Quad.easeOut, delay:1.5});
TweenMax.to(zeus, 1, {css:{width:"758px"}, ease:Quad.easeOut, delay:2});
TweenMax.to(introCopy, 1, {css:{opacity:1}, ease:Quad.easeOut, delay:3});
TweenMax.from(introCopy, 1, {css:{top:"50px"}, ease:Quad.easeOut, delay:3});

}

Link to comment
Share on other sites

A few questions:

 

1) Would you download the latest version of GSAP and see if that improves things at all for you? Obviously revert back to putting jQuery after the tweens.

 

2) What happens if you run this before any of your tweens?: TweenLite.ticker.useRAF(false);

 

And, no, I don't think there's any magic behind jQuery.animate() that would force a page render any more than a regular TweenLite that's affecting the same property would. If you update a CSS property on an element, it should get repainted in the browser.

Link to comment
Share on other sites

I tried downloading the latest version and still had the animation not play sometimes on reload (mobile safari).

 

I tried adding in TweenMax.ticker.useRAF(false); (I am using TweenMax for pause/resume) and had the same result (sometimes would not display).

 

Weird yeah?

Link to comment
Share on other sites

I think Carl is right - the browser (or CPU) is just overwhelmed with rendering everything at once at initial startup, causing the sluggishness. that's my best guess - I tried on an iPhone and things almost always played fine, but occasionally bogged down a bit because of all that's going on.

Link to comment
Share on other sites

Quick side note... visit http://tools.pingdom.com/fpt/ and test the load time and check out the results.

 

It gives a score of zero for leveraging browser caching. Once you get this caching aspect addressed you'll likely see diminished issues on reload/refreshes. Also, putting all of your javascripts before the </body> tag will also ensure a bit of latency on init() is resolved, though that can have some adverse affects to the page depending on styles/html, etc. - it's easy to work around those oddities though.

 

With .htaccess, if supported on your server, you can specify the various headers and module caching stuff for specific file types and other things that can help with this sort of issue.

// .htaccess code for caching and gzipping
// (typical setup but you should customize to your server)
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 month"
ExpiresByType image/jpeg "access 1 month"
ExpiresByType image/gif "access 1 month"
ExpiresByType image/png "access 1 month"
ExpiresByType text/css "access 2 days"
ExpiresByType application/pdf "access 30 days"
ExpiresByType text/x-javascript "access 2 days"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 3 days"
</IfModule>
<IfModule mod_headers.c>
 <FilesMatch "\.(js|css|xml|gz)$">
Header append Vary Accept-Encoding
 </FilesMatch>
</IfModule>

  • Like 1
Link to comment
Share on other sites

Thanks for looking into this everyone.

 

The fact remains that the animation had spotty results when I left out the jQuery.animate on mobile safari.

 

With the jQuery.animate function firing first it has NEVER missed the entire animation on reload.

 

Sure, caching would be great thing to implement, but its not the cause or solution.

 

I'm pretty baffled as to why this solved the issue.

Link to comment
Share on other sites

Just to be clear, you're saying that you only moved that jQuery statement up a few lines so that it executes right before the tweens, but they all get called in the same block, right? It isn't as though previously you ran the jQuery line AFTER all the tweens were finished (durations elapsed), right? All you did was reorder the calls in a block.

Link to comment
Share on other sites

Are you 100% positive that's the only thing you changed? I really can't see anything that would explain the difference, and I couldn't replicate what you were describing.

 

That being said, I did discover a Safari/iOS bug which I describe here:

http://forums.greensock.com/topic/6398-page-not-updating-correctly-in-safari-and-ios/page__p__23112#entry23112

 

So please download the latest version of GSAP and let me know if that works well without using jQuery.

Link to comment
Share on other sites

Yes, 100% sure that the only thing I change is adding in the jQuery.animate call before any tweens.

 

I tried out the new version, and I am getting weird flickers on the initial animation.

 

I am beginning to wonder if it has something to do with tweening a div's width with a background image.

 

Check this on iOS....

 

http://thegeminisociety.com/index_fix.html

 

Works great on safari desktop.

 

Really wish I could help you track this one down!

Link to comment
Share on other sites

Well I've had an enlightening 24 hours looking into this. And when I say "enlightening", I mean nightmarish :) Safari in iOS is absolutely craptastic. And Steve Jobs ripped Flash for being buggy? Who's the pot and who's the kettle?

 

Anyway, here are my findings...

 

First, I'll mention the bugs in Safari for iOS:

  1. Changes to "top" or "left" properties are completely ignored if they're made at the same time as changes to any transform property like rotation, scale, skew, x, y, etc. (how the heck could Apple miss that?!). However, if you set -webkit-perspective to a non-zero value, it fixes this bug. I described the issue and provided proof with sample code in this post: http://forums.greens...3112#entry23112
  2. The display often doesn't get repainted properly after transform changes are made until you scroll (or sometimes tap a link). The properties are set correctly, but it's like the screen doesn't show it until you scroll to kick-start the renderer. Again, setting a non-zero -webkit-perspective solves this problem.
  3. If you define a -webkit-perspective on an element, it causes random flickers when you resize that element, particularly one with a background-image.

So the fix for the first 2 actually causes the 3rd bug!

 

After tons of hacking, I discovered one recipe that seems to resolve all of the issues above. Set -webkit-backface-visibility to "hidden" AND make sure z-index is set to some number (doesn't really matter as long as it's not blank). Of course most people will have no idea that they need to implement these styles to avoid Safari bugs, so the latest version of CSSPlugin (which is also inside TweenMax) automatically does it for you. For Safari (only), when you make some sort of transform change (like rotation, x, y, scale, or skew), it will ensure that -webkit-backface-visibility and z-index are set.

 

Please download the latest version and give it a shot.

Link to comment
Share on other sites

Oh, and by the way, when I was glancing at your code, I noticed that you were using a rather verbose style which is totally fine, but I wanted to make sure you knew that you could consolidate things quite a bit. For example, here is a chunk of your existing code:

 

OLD:

tl = new TimelineLite();

tl.eventCallback("onComplete", removeMobileTimeline, [tlObj]);

tl.insert(TweenMax.from($('#love1'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), 0);
tl.insert(TweenMax.from($('#love2'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), .2);
tl.insert(TweenMax.from($('#love3'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), .4);
tl.insert(TweenMax.from($('#love4'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), .6);
tl.insert(TweenMax.from($('#love5'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), .8);
tl.insert(TweenMax.from($('#love6'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), 1);
tl.insert(TweenMax.from($('#love7'), .5, {css:{autoAlpha:0, top:"-50px"}, ease:Quad.easeOut}), 1.2);

tl.seek(0);
tl.stop();

 

You can use the staggerFrom() convenience method and pass a configuration parameter to your TimelineLite to reduce all that code to 2 lines:

 

NEW:

tl = new TimelineLite({onComplete:removeMobileTimeline, onCompleteParams:[tlObj], paused:true});
tl.staggerFrom([$('#love1'), $('#love2'), $('#love3'), $('#love4'), $('#love5'), $('#love6'), $('#love7')], 0.5, {css:{autoAlpha:0, top:"-50px"}}, 0.2);

 

I removed the ease:Quad.easeOut too because that's the default.

 

Again, your old way was perfectly fine and you might prefer that style but I wanted to make sure you knew about the convenience methods and the fact that you can tween arrays of values pretty easily.

 

Happy tweening!

Link to comment
Share on other sites

Wow, what a horrific bug in mobile safari... Glad I could help you uncover it.

 

And yes, I really should implement the stagger from code, next on my list!

 

Thanks for being so persistent on tracking down/fixing odd and strange bugs, its why I use your products!

 

 

I will try your new version and let you know how it performs!

Link to comment
Share on other sites

Found the problem and it has nothing to do with TweenLite/Max :) (phew!)

 

Your code isn't waiting for the page to fully load before starting the animations. You've got the following code at the bottom of your page:

 

$(document).ready(init()); //<--BAD

 

There are two reasons this code is problematic:

  1. You have "()" after "init", meaning that it calls it immediately. You're supposed to pass a function into jQuery's ready() method, but you're literally passing the return value from init(). I think you meant $(document).ready(init).
  2. jQuery's onReady() method is for triggering a function when only the DOM elements have finished loading (the HTML), but that does NOT include images! So even if you fix your "()" problem from #1 above, it won't solve your problem because your animations at the top depend on the background-images being loaded first. For jQuery's onReady() docs, see http://api.jquery.com/ready/

So you should switch to either using a regular onload="init()" inside your <body> tag or use jQuery's load() method on the window like this:

 

$(window).load(init);

 

And for the record, I tried toggling your jQuery animate() method on and it did NOT fix the loading/display issue. I was still seeing exactly the same problem where it appeared as though the animation was suddenly jumping in part-way through instead of starting at the beginning, but as we have discovered, that makes perfect sense because the widths of those divs were being animated open without the images being there yet, thus when they finally popped into place, the animation looked like it was jumping.

 

Make sense?

Link to comment
Share on other sites

Oh man, I have to get used to how JS works with calling a function and passing a function!

 

I updated my code to do this:

 

$(document).ready(main.init);
$(window).load(main.animateAboutUs);

 

I do all my caching, etc in init and now call the animate function on window.load.

 

Everything seems to be working perfectly now! At least we uncovered an issue within webkit lol.

 

But seriously, thanks for your help looking into this... I will be around to help uncover more issues I'm sure :D

Link to comment
Share on other sites

  • 2 weeks later...

css3 - feature

For Safari (only), when you make some sort of transform change (like rotation, x, y, scale, or skew), it will ensure that -webkit-backface-visibility and z-index are set.

 

Please download the latest version and give it a shot.

 

I tried downloading and using the v-12. But i guess the support for css3 - rotateY is yet to be plugged in.

 

I want to implement a looped sequence of animation - first translate the element then apply rotateY on it

When i run my demo, its working well on other browsers BUT iOS mobile- safari, i notice the Z-order (misbehaving for dynamically created elements whom the webkitTransform is applied) and flickering issue.

 

I tried adding the zIndex and backface-visibility- flickering is gone. But even if i set the z-Index still the elements are not displayed in proper stacking order. This happens only after i add the rotateY code

document.getElementById(sDivName).style['z-index'] = nCurrentIndx
document.getElementById(sDivName).style['-webkit-backface-visibility'] = 'hidden'
document.getElementById(sName).style['-webkit-transform'] = 'translate(-50px, 0px) rotateX(0.4rad) rotateY(3.14rad)'

 

It would be great, if you could guide me with this.

Link to comment
Share on other sites

I think that the problem is you're referencing the properties in JavaScript incorrectly - you're using the css names (with dashes) instead of the camelCase style which is required in JavaScript. For example:

 

//BAD:
document.getElementById(sDivName).style['-webkit-backface-visibility'] = 'hidden'

//GOOD: 
document.getElementById(sDivName).style.WebkitBackfaceVisibility = 'hidden'

 

Does that help?

Link to comment
Share on other sites

Thanks for pointing out camelCase style. I will always keep that in my mind hence on.

 

I changed it in my code but now i see flickering and z-index issue together.

 

 

 

i am just writing down my approach (let me know if anything wrong in my approach )

- create dynamic div elements (cards style with front side and back side)

- position it and translate it location from where the animation should be started (say location A (100,100))

- on event of click - start translation from location A to cards origin position (0,0)

- on webkitTransitionEnd event, start the flipping of card element.(rotateY(180deg))

 

code for card creation

function CreateCardStructure(sDivName, loc, parentContainer, nFake) {
  // create parent -
  var objCardParent = document.createElement('div');
  objCardParent.setAttribute('id', 'parent' + sDivName);
  // add to stage
  document.getElementById(parentContainer).appendChild(objCardParent);
  // add required style
  document.getElementById('parent' + sDivName).className = 'cardContainer';
  // create card
  var objCard = document.createElement('div');
  objCard.setAttribute('id', sDivName);
  //add to parent
  document.getElementById('parent' + sDivName).appendChild(objCard);
  //create front nd back with styles to it
  var sInnerHTML = '<span id="f' + sDivName + '" class="front side">' + '</span>' + '<span id="b' + sDivName + '" class="back side">' + '</span>';
  //add images to front nd back
  var imgFrnt = new Image()
  imgFrnt.src = loc.front
  imgFrnt.setAttribute('id', 'imgFrnt' + sDivName);
  var imgBck = new Image()
  imgBck.src = loc.back
  imgBck.setAttribute('id', 'imgBck' + sDivName);
  //add it to card
var element = document.getElementById(sDivName).
 element .innerHTML = sInnerHTML;
  document.getElementById('f' + sDivName).appendChild(imgFrnt);
  document.getElementById('b' + sDivName).appendChild(imgBck);
  element.style.marginLeft = loc.x
  element.style.marginTop = loc.y
  element.style.position = 'absolute'
 element.style.zIndex = nCurrentCard
element.style.transformOrigin = '123px 0px'
 element.style.webkitTransformStyle = 'preserve-3d'
 element.style.webkitBackfaceVisibility = 'hidden'
  element.style.webkitTransform = ' translate(' + (objDealPosition['xPos'] - (nPadding * nCurrentCard)) + 'px, ' + objDealPosition['yPos'] + 'px)'
 }

 

 

 

translating the card on event to origin

element.style.zIndex = nCurrentCard
 element.style.transformOrigin = '123px 0px'
element.style.webkitTransformStyle = 'preserve-3d'
 element.style.webkitBackfaceVisibility = 'hidden'
 element.style.webkitTransitionDuration = '1s'
element.style.webkitTransform = 'translate(0px, 0px)'

 

on end of 'webkitTransitionEnd' event

element.style.visibility = 'visible'
  element.style.position = 'absolute';
 element.style.zIndex = nCurrentCard
 element.style.transformOrigin = '128px 20px';
  element.style.webkitTransformStyle = 'preserve-3d'
  element.style.webkitTransitionDuration = '0.5s';
element.style.webkitBackfaceVisibility = 'hidden'
 element.style.webkitTransform = 'rotateY(180deg)'

 

I am in fire-fighting mode for this project and this flipping module is just killing me!!

It would love to hear back from you on this.

Link to comment
Share on other sites

Oh, you're not even using the tweening engine? It looks like you're using CSS3 transitions. That's fine, but it's really not something we can help with here (these forums are for questions about GreenSock tools). I don't have much experience yet with 3D or CSS3 transitions and this definitely sounds like a bug with iOS/Safari (which I'm pretty powerless to resolve). I wish I could help more. :(

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...