Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
srmark

Performance issues on android devices

Recommended Posts

I'm working on a digital signage system's content editor interface, which produces HTML5 pages. I've recently replaced the animation engine of these generated pages from pure CSS3 to GSAP and I'm experiencing some cases when the content animation has strong lag and freezes on our android devices, while on Windows/latest Chrome it runs well. I also tested some GSAP codepen demos on the android devices, and those run well, so I think I'm doing something wrong here, and would like to get some help.

 

One of the devices I tested on (possibly the strongest hardware): http://www.gearbest.com/tv-box-mini-pc/pp_282317.html

 

The example page: https://storage.googleapis.com/content.myshopdisplay.com/193/1377/8401/index.html

 

About the code in the page:

The page has a transform scale applied to stretch the content to full screen (this is not animated).

 

The page first moves in letters one-by-one by animating the top and left properties, to make the word EURONICS. This runs laggy but still ok on android. After that a big background picture fades in by opacity animation, then 4 stars also appear on the right side by opacity animatin in a delayed sequence. The strongest lag happen when the big background picture fades in. It takes about 1 second on PC to animate that, and on android it takes about 30-60 seconds.

 

Each page element has their custom CSS values in the inline style attribute. The animatin timelines are generated at the start of the page:

I create a timeline for each element

new TimelineMax({repeat: repeatAnimation, repeatDelay: 0, paused: true, smoothChildTiming: true});

Then I iterate over the style properties that should be animated (not all on an element's style attribute, I store the animated properties in a separate container), I create a timeline for each of these, this constructor function gets no arguments. After that I iterate over the time positions I stored. If this is the first value at position 0, I use the set() function:

propertyTimeline.set(targetElement, valueObject, 0);

If it's not the 0 position I calculate the exact duration of the tween and add it to the timeline with the to() function:

propertyTimeline.to(targetElement, duration, valueObject);

When all values processed for a property I add the property timeline to the element's timeline at position 0. The element's timeline contains only these property timelines. When this is done to all elements I iterate over all of the element timelines and call play(0) on them. I do not add the element timelines to a main timeline because they can have different length, and they can repeat, and they need the ability to restart at different times.

 

It's understandable that too many effects can cause lag, but this page is not too effect-heavy in my opinion, so I'm clueless why is it so laggy. It is also very inconvenient that this lag actually extends the full duration of the animation, while with CSS iirc it only skipped frames when it was too laggy, but It finished the animation at the desired time (this is important for our system because these pages are being played one after one, and the pages change at a fixed time)

 

What could be wrong here?

 

Thanks in advance for your help!

 

Roland

Link to post
Share on other sites

Hello srmark, and Welcome to the GreenSock Forum!

 

The performance issue on mobile your seeing is due to you animating top and left instead of x (translateX) and y (translateY).

 

I would strongly suggest that you never animate top and left CSS position offsets. You should only use CSS top and left position offsets in your style sheet to set the initial position you want. And then you would animate using transforms like x instead of left and y instead of top. The reason being is that top and left only animate on a pixel level, do not use the GPU, and cause re-layout to render. Whereas animating x and y will animate on a sub-pixel level, and can take advantage of hardware acceleration for smoother performance.

 

So just change the CSS property left to x and top to y in your tweens to help improve performance and get a smoother animation.

 

I am a little confused on what your trying to do since we cant really test your code in a live editable environment.

 

Also if you are still having an issue please create a limited codepen example so we can better help you. We love code we can test and edit live.

 

 

Thanks!

  • Like 3
Link to post
Share on other sites

Hi Jonathan,

Thanks for the quick reply!

While I was making a codepen I found a bug in my generator code which produced the shadow CSS, that caused the drop-shadow to be applied 4 times. I fixed that, so its a bit better.

 

Here is the codepen I made, it's not as laggy as my generated page on android, but there is still a big difference between the PC and the android speed on this:

See the Pen YqNrXe by srmark (@srmark) on CodePen



I also applied the changes you suggested about left top x y, but the main problem is still the opacity fade being slow. I also noticed that the background picture on the page had a hue-rotate filter, just as in the codepen, and that also has some impact on the animation speed.

 

So overall my question is, can I make that codepen faster by maintaining the same functionality?

 

And as a secondary problem, changing the left and top to x and y, caused another weird bug. First all the elements positioned had their position applied twice, or seemed like so. I think this was due to the element having top left inline, and when the animation changed the x and y, it just added a transform to the element inline, not changing the top and the left at all, but the transform values were not relative but absolute to the element's original position.

 

So I also added that wherever I add an animation that changes x or y, I also set the left or top of the element to 0, like this:

if (propertyNameAsParam == "x") {
propertyTimeline.set(currentTag, {left: 0}, 0);
}
if (propertyNameAsParam == "y") {
propertyTimeline.set(currentTag, {top: 0}, 0);
}
propertyTimeline.to(currentTag, duration, valueObject);

This code fixed the problem on Windows/Chrome completely, but caused a problem that on android all elements collapse to the top left corner, and they dont animate their position properties at all.

 

This is the new page: https://storage.googleapis.com/content.myshopdisplay.com/193/1377/8551/index.html

 
This is a preview image taken on the android device: image link
 
It seems like GSAP can't animate the x or y on android (5.1) at all. 

 

I can make another codepen for this later if you want, but my work hours are over for now, and I wanted to share, so hopefully you can spot the problem in this.

 

Thanks again!

 

Roland

Link to post
Share on other sites

I tested your example on Android 5.1 Droid Turbo on latest Mobile Chrome, and it animated.

 

Make sure anytime you set position absolute that you also include the left and top property. Even if they are at 0. So this way you define it for the browser. Also keep in mind that anytime you use position absolute on an element to animate, you must use the CSS property position relative, so your absolutely positioned elements are positioned relative to their parent.

 

If it was me, i would only have top:0px and left:0px inside your style-sheet and not anywhere inline on the tag or tween your animating. Some browsers need that defined in your style-sheet. This is due to top and left having a default of auto. And auto can calculate different in each browser, instead of being zero (0)

 

Once you have your elements top and left set in your CSS style-sheet. And have position relative on the parent of your absolutely positioned divs. then your elements will animate correctly.

 

Also add height 100% on your html and body tag in your style-sheet, so the element with position relative will have its height inherited from the body and html tag.

/* makes sure elements in the body inherit height 100% */
html, body {
    height: 100%;
}

Try changing opacity to autoAlpha

 

autoAlpha is a special property that is part of the GSAP CSSPlugin. It is better for performance.

 

http://greensock.com/docs/#/HTML5/GSAP/Plugins/CSSPlugin/

  • autoAlpha
    Identical to opacity except that when the value hits 0 the visibility property will be set to "hidden" in order to improve browser rendering performance and prevent clicks/interactivity on the target. When the value is anything other than 0, visibility will be set to "inherit". It is not set to "visible" in order to honor inheritance (imagine the parent element is hidden - setting the child to visible explicitly would cause it to appear when that's probably not what was intended). And for convenience, if the element's visibility is initially set to "hidden" and opacity is 1, it will assume opacity should also start at 0. This makes it simple to start things out on your page as invisible (set your css visibility:hidden) and then fade them in whenever you want.
//fade out and set visibility:hidden
TweenLite.to(element, 2, {autoAlpha:0});

//in 2 seconds, fade back in with visibility:visible
TweenLite.to(element, 2, {autoAlpha:1, delay:2});

Keep in mind that anytime you use CSS box-shadow, text-shadow, and filters. That can cause bad performance on mobile devices due to the amount of paints and compositing those CSS properties can cause to render.

 

Try changing opacity to autoAlpha in your tweens

// so change opacity 
tl.to("#logo", 2, {opacity: 0});
tl.to("#logo", 2, {opacity: 1});

// to use autoAlpha instead
tl.to("#logo", 2, {autoAlpha: 0});
tl.to("#logo", 2, {autoAlpha: 1});

See the Pen rejpoa?editors=0100 by jonathan (@jonathan) on CodePen

 

Does that help? :)

  • Like 4
Link to post
Share on other sites

I want to re-emphasize what Jonathan said  - CSS filters are MASSIVE performance-killers. Browsers just don't render them well. It has nothing to do with GSAP. 

 

Also, I noticed the markup on your original page was weird, like data-styleobject="{"left":"-200px","top":"264px","width":"107px","height":"332px"}" - notice the quotes are all wrong (not nested properly). That probably has nothing to do with the performance, but I wanted to mention it anyway :)

 

My guess is that if you remove the CSS filters completely, you'll see a huge improvement in performance. Perhaps you could apply the shadows in a different way, like as a PNG or something. That'd be significantly "cheaper" for the browser to render. 

  • Like 4
Link to post
Share on other sites

Hi,

Thanks again for the replies. After a nice debugging session I found the problem that was causing the moving animations not to be working on our android devices. I had a routine at the start of the page which copied the inline transform values into the browser-specific transform styles such as -webkit-transform, -moz-transform etc, to make it work on all of our devices (this was the intended behavior).

 

I logged one of the element's transform and -webkit-transform properties while the animation was running, and on Windows GSAP modified both of them, while on Android GSAP only modified the transform property, and not the -webkit-transform at all (which hold a basic value of scale(1) rotate(0), that was set only once at the beginning). So it seems like GSAP detected that the device supported the simple transform property, so it didn't bother setting the webkit prefixed one, but the browser actually used the webkit prefixed one when both was set, and I saw from the periodical log that GSAP was working, because the transform property got modified and hold the correct values, but it didn't prevail. I had to disable the above mention routine of mine to make the move animations work.

 

EDIT: The above problem only occurs if both transform and -webkit-transform are set inline, and the -webkit-transform is after the transform, I was able to make a pen to show this problem:

See the Pen PNWXEO by srmark (@srmark) on CodePen

It works on Windows, the rectangle moves back and forth, but on Android it doesn't move at all. Making the -webkit-transform come first in the inline style followed by the transform solves this issue, because it seems like the latter one prevails.

 

Overall, using the x and y at the animation seem to help a lot on the performance after I could make it work. About the value calculation, I reverted setting the top and left properties of the elements 0, and instead I leave them at their original values (always set), and substract their original values from the x and y before adding them to the animation, this yields the correct position. I also applied the autoAlpha property, instead of the opacity, but didn't see any noticable impact on the performance.

 

We also tested, and removing the filter effects also had huge impact, so I'll keep this in mind, but also these contents are made by our customers, so we can either remove the full functionality from our software, or just warn them to not use too many of them, but in the latter case the user can still make a screen full of 8px sized text blurred, shadowed spinning zooming and moving if they want, and it will fry their device (this was an actual test page I made for stress tests :P).

 

Please remember that these contents are auto generated in our system, so there are some restrictions and limits in the coding practise, some of them are because many contents exist with legacy code. I'm well aware that techniques like adding the shadow to the elements as an image instead of pure CSS is much easier to render for the browser, as Jack suggested, but these are improvements that are simple and convinient only for regular websites' static content like logos, but In my case I would have to find a solution that makes it for dynamic contents, every time a user makes a content in our system, then run it to generate images, store them etc, so it is complicated and resource-hungry (at the generation).

 

Jack, the markup you copied only appears so in the debugging tool of the browser, in the page's source it appears like this: data-styleobject="{"left":"1318px","top":"90px","width":"350px","height":"350px","opacity":"0"}" so it doesn't cause any problems :). This is the result of making a javascript object a string by JSON.stringify and setting it as an attribute of the element.

  • Like 1
Link to post
Share on other sites

That's great - glad to hear you got it all figured out. Thanks for reporting back. Happy tweening!

Link to post
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.

×