Jittery text during scaling animations with JavaScript - javascript

When using scaling to change the size of an HTML element containing text, the text jitters during the animation, but only if being animated with JavaScript libraries.
The jittering is most visible when the animation is slower and the text is smaller. I can't seem to figure out what causes it or how to get rid of it.
This jittering does not occur during CSS animations or animations using the fairly new JavaScript Web Animations API. It also doesn't seem to occur in some browsers. (On my iPhone)
To easily compare the different methods of animating the scaling of an element and how they appear, I made a CodePen for convenience. Before checking it out, note these points:
All the animations are using some form or imitation of the CSS property transform: scale(num); for the animation and have the same easing and duration so they can be compared more easily.
Although the jittering appears on macOS too, it is almost impossible to see on Macs with retina screens because of the high resolution.
The results I got are a reflection of the appearance of the animations on a Windows 10 machine in Google Chrome 59, although for me Microsoft Edge also showed the same results.
So my question is this: How can I prevent the text from jittering or becoming blurry when animating a scale property with JavaScript? How can I make the text in my JavaScript scale animations appear just as smooth as they do when using CSS?
You may be wondering why I don't just use CSS. The answer is because I'm frustrated with how limited CSS animation is. I would like to use advanced easing functions beyond the capabilities of a simple bezier curve (like Robert Penner's bounce and elastic functions), and use different easings on hover when the mouse enters and exits the element. This s completely my own opinion, but so far the only painless way I've found to do this is with JavaScript libraries. Besides their functionality relating to easing, most seem to offer many other capabilities which make animating much more effortless. If you know of a better way to get all the functionality I need please let me know!

What you are encountering are differences in a browser's layerizing strategy. You'll find that all the examples appear smooth in Firefox. That's because Firefox detects when script is changing a property that can animated using layers and creates a layer in response.
Although all browsers create layers when needed for declarative animations (CSS animations, CSS transitions, Web Animations API animations, and even SVG SMIL animations in some cases) not all browsers do it for Javascript animations. So, for those browsers you need to try to trick the browser into creating a layer (or, you could just file a bug on the browser, since it really should do this for you!).
Until recently, using will-change: transform was the recommended approach to get a browser to create a layer. However, Chrome changed its rendering strategy and now will-change: transform can produce very blurry results with scale animations in Chrome. Some people have succeeded in tricking Chrome to layerize at a higher resolution initially and then scaling their element down before animating. This is really unfortunate to have to do this and I can only encourage you to petition Chrome to fix this.
Also, the examples using "with HA" are not accurate. The CSS animation in (1) will also use hardware acceleration in every browser I know of--there's no need to add perspective in. Unfortunately, there is a lot of misleading information in this area (e.g. some articles claim animations can run on the GPU but that's simply not true). At the risk of self promotion, you might find an article I wrote on this last year helpful.

Related

Can I force the browser to rasterize elements before they become visible?

Call me crazy, but I'm working on a game using vanilla DOM and TypeScript. It's not action-heavy, but there are some animations going on, which are driven from JavaScript (too complex to do in CSS).
I'm already applying the common trick of translateZ(0) (called null transform hack or less accurately silver bullet) to pull animated elements into their own rendering layer, and I'm animating nothing besides compositor-only properties (transform and opacity). This works beautifully: during the game, everything feels buttery smooth, even on older mobile devices.
The problem is during the start of the game. At that moment, about 70 individually transformed and animated elements enter the page one by one over the space of a few seconds, by animating their opacity from 0 to nonzero. This is causing visible stutter during the animation.
My guess was that Chrome is being too clever here, and will only rasterize each element at the moment it first becomes visible. A quick check with the dev tools confirms this, as there's a lot of rasterization going on even during the animation:
I would prefer to rasterize all these elements once, before the animation starts, and only then trigger the animation. But how can I force rasterization of elements that aren't yet visible, without showing a flash of them to the user?
I'd be happy with a Chrome-only approach, but cross-browser would be even better.

JQuery .animate Really Choppy in Chrome Extension

I have a JQuery .animate function.
It switches between two forms.
It toggles height and opacity.
When the two forms are the same height (and the popup does not resize) the animation is smooth. When the popup has to resize, the animation becomes choppy and a thick black border appears around the popup for a couple of seconds.
Is there anyway of smoothing the animation or should I switch to CSS for my animations?
Right now, the extension is that when a label is clicked a new form appears on top of the old one.
Most likely your jQuery animate function uses 2D animations. Look into using 3D translate and transform instead.
Why would 3D be faster than 2D you ask?
Because 3D gets accelerated and rendered using the GPU, 2D does not.
I did the same thing myself not long ago and the results are vastly superior.
It is 2017. You definitely should switch to CSS transitions.
1) Don't use jQuery in Chrome extensions. It's a browser standardisation framework and you're using it in a component that only works in one browser. Instead use advanced features (such as passive events) that Chrome supports but jQuery does not.
2) Avoid changing the height of elements where that will change the size/position of other elements (or the extension pop-up).
Instead use just opacity and transform CSS elements on an absolutely positioned element to ensure that the entire animation can be handled by the GPU without reflow.

Does CSS transition perform bettern than DOM animation?

I was running something which does number scrolling using ScrollerJS. It supports two modes : CSS transition and DOM animation. When I was using the DOM animation mode, I find sometimes the scrolling is not smoother than that of CSS transition.
So I am wondering whether CSS transition performs better than DOM animation generally? Is there any proof or testing that shows this?
CSS transition : CSS3 transition/transform property which transforms an element
DOM animation : Traditional DOM animation which changing the CSS top property continuously.
In short, yes. Doing it in CSS allows the browser to optimize it, e.g. using hardware acceleration.
If you manipulate the DOM, the browser generally has to re-render the content, which is usually slower.
DOM manipulation is typically used to support older browsers where CSS animation is not supported (or poorly implemented).
From http://scrollerjs.pixelstech.net/#about
If CSS transition is supported in a browser, CSS transition will be
the preferred option for animation.
If in old browsers where CSS transition is not supported. DOM
animation will be chosen automatically.
However, note that as usual, things are never completely straightforward, and no generalization is completely true... There are javascript animation libraries out there that can rival or sometimes even outperform CSS-based transitions/animations, and they are usually more flexible. Here's some light reading:
http://davidwalsh.name/css-js-animation
https://css-tricks.com/myth-busting-css-animations-vs-javascript/
This question isn't too hard to answer.
A DOM animation uses your CPU for it's calculations and since an animation is quite heavy on the CPU it'll sometimes 'lag' which is when you see artefacts on the screen.
CSS3 transitions however are able to use hardware acceleration which uses the GPU of your computer (if it has one ofc :D). Since your GPU is much stronger and better at doing things like animating, you'll barely notice any lag if any.
This question is not easy to answer because in different cases some kind of animation performs better than the other.
I think this article could be more than interesting if we are talking (seriously) about performance between CSS and DOM animations.
If you are going to work a lot with animations and you are worry about the performance I suggest to try a more professional library like GSAP, they also have a scroll plugin.

IE8 transition on hover

I want to use transition effect on hover for IE 8 like in this example:
http://jsfiddle.net/evcL2/10/
According to this site (is working only on ie) that is possible (use trasntion option and fade effect) but I am not able to use it. Can someone help me a little bit with that script, for me is simportant to have that transition on hover only for background color.
Thank you.
IE8 doesn't support CSS3 transitions. You'll have to fake it using JavaScript tweens, or settle for IE9 support. IE8 users don't deserve nice looking websites anyway :-)
But if you're in the awkward position of being tasked with creating IE compatible stuff, take a look at this MSDN introduction to Filters and Transitions. It appears that even the IE specific transition filters require JavaScript to work, so you might as well go with the proper JavaScript solution of using jQuery.animate. With a small plugin it can animate colors. Here's an example on JSFiddle.
For some reason the website you suggested doesn't render properly in my browser. However, I think you may be attacking the problem wrongly. I would use jQuery's $.animate() function for this, as it is very cross browser and can animate gradual changes in many css properties.

CSS3 Transform Animation doesn't render so well in Safari/UIWebView

I'm developing an HTML5 app for mobile/touch device deployment and are utilising PhoneGap and only targeting the iOS platform for the moment (Webkit).
My issue occurs with the CSS3 transitions (and it happens to regular jQuery animations as well) in that Webkit tends to do some strange things. For instance, in the code available to view here (http://jsfiddle.net/lvl99/dSjcj/) when you step through the pages, going back in the sequence (i.e. from page 5 to 1) will render the animation fine, however stepping forward (i.e. from page 1 to 5) will produce inconsistent rendering, mostly on the side of ugly (remember to view it in Safari. I've been using Safari 5.1.7).
I was originally developing using the jQuery Mobile framework, but the key functionality that I was using was the page routing through hashtags and the transitions, but since I had these issues with the transitions, I tried developing a simpler solution to avoid any JS/CSS conflicts with jQM. Alas, it's possible that the errors I've been coming up are actually Safari/Webkit related.
I originally used jQuery.animate() on the left property, to now using CSS3 transform technique similar to the jQM way of doing things, also to help with speed and test whether it would be more willing to render properly. Both haven't worked to varying degrees of unworkingness.
Fortunately, Firefox renders everything fine. It has no problems, however Firefox isn't the target platform and when the project is compiled within Xcode in the PhoneGap environment, it expresses the same problems that Safari has with it. When I was still using jQM with an earlier development version, Safari would render it fine (including Safari on the iPad Simulator), however UIWebView wouldn't. This made me think that perhaps it was a Nitro JS engine issue (as in, perhaps UIWebView didn't have the speed/power/capability to render the transition properly -- I've attempted to transfer all animations to CSS3 to relegate the rendering operations to the GPU).
I've used various plugins like jQuery Transit, jQuery Animate Enhanced, and TransformJS. I also tried coding my own custom transition handler within jQM and it didn't render properly (although it came the closest: worked in Firefox and Safari, just not in UIWebView).
I've had inconsistent results regarding transitioning elements with different types of content too: video, images, floated elements, multiple paragraphs are all I've tested. There was at some stage too issues with transitioning to/from the extreme ends of the sequence (i.e. 1 and 5), but now my issue is just that ascending page transition (i.e. 1 to 5).
I've spent a number of days on this, trying to address this seemingly small issue, but it's quite integral to the user experience having slide transitions like this which are contextual based on the direction the user is moving through the app. The easiest solution is to just remove the transitions, but if there's some way to understand what exactly Webkit/UIWebView is having trouble with, to create some solution for it. It's no doubt related to the flicker issue jQM experiences with transitions too. A lot of the CSS fixes for those people suggested on the web didn't work either, such as -webkit-backface-visibility: hidden and setting a default transform property -webkit-transform: rotateX(0).
It looks like the problem is that it's not animating the next item from the right (when moving up 1->2->n) but rather just '.show()'ing it when the previous item is done animating out.
Gimme a sec to step through the .js
...
Ok, I think I know what it is, what it's doing is, when it's moving right-to-left (numerically up) you can't see the new page (higher number) coming in from the left, because 'left' is moving from 100% -> 0% because the smaller number is moving out.
Ok, I think that's wrong...
If you change the 100% to 92.5% in the #-webkit-keyframes slideinleft and #-moz-keyframes slideinleft declarations then it should work for you, unfortunately I can't tell you why exactly as we (work) avoid CSS transformations as we do a lot of corporate work and so still need to support IE7+ and sometimes even 6 :(
Note that you can try a value other than 92.5% I just wanted to find the lowest sensible value that worked for you (95% didn't work)

Categories

Resources