7 Performance Tips for Jank-free JavaScript Animations

Share this article

7 Performance Tips for Jank-free JavaScript Animations

The role of web animation has evolved from mere decorative fluff to serving concrete purposes in the context of user experience — such as providing visual feedback as users interact with your app, directing users’ attention to fulfill your app’s goals, offering visual cues that help users make sense of your app’s interface, and so on.

To ensure web animation is up to such crucial tasks, it’s important that motion takes place at the right time in a fluid and smooth fashion, so that users perceive it as aiding them, rather than as getting in the way of whatever action they’re trying to pursue on your app.

One dreaded effect of ill-conceived animation is jank, which is explained on jankfree.org like this:

Modern browsers try to refresh the content on screen in sync with a device’s refresh rate. For most devices today, the screen will refresh 60 times a second, or 60Hz. If there is some motion on screen (such as scrolling, transitions, or animations) a browser should create 60 frames per second to match the refresh rate. Jank is any stuttering, juddering or just plain halting that users see when a site or app isn’t keeping up with the refresh rate.

If animations are janky, users will eventually interact less and less with your app, thereby negatively impacting on its success. Obviously, nobody wants that.

In this article, I’ve gathered a few performance tips to help you solve issues with JavaScript animations and make it easier to meet the 60fps (frame per second) target for achieving smooth motion on the web.

#1 Avoid Animating Expensive CSS Properties

Whether you plan on animating CSS properties using CSS Transitions/CSS keyframes or JavaScript, it’s important to know which properties bring about a change in the geometry of the page (layout) — meaning that the position of other elements on the page will have to be recalculated, or that painting operations will be involved. Both layout and painting tasks are very expensive for browsers to process, especially if you have several elements on your page. As a consequence, you’ll see animation performance improve significantly if you avoid animating CSS properties that trigger layout or paint operations and stick to properties like transforms and opacity, because modern browsers do an excellent job of optimizing them.

On CSS Triggers you’ll find an up-to-date list of CSS properties with information about the work they trigger in each modern browser, both on the first change and on subsequent changes.

CSS Triggers Website

Changing CSS properties that only trigger composite operations is both an easy and effective step you can take to optimize your web animations for performance.

#2 Promote Elements You Want to Animate to Their Own Layer (with Caution)

If the element you want to animate is on its own compositor layer, some modern browsers leverage hardware acceleration by offloading the work to the GPU. If used judiciously, this move can have a positive effect on the performance of your animations.

To have the element on its own layer, you need to promote it. One way you can do so is by using the CSS will-change property. This property allows developers to warn the browser about some changes they want to make on an element, so that the browser can make the required optimizations ahead of time.

However, it’s not advised that you promote too many elements on their own layer or that you do so with exaggeration. In fact, every layer the browser creates requires memory and management, which can be expensive.

You can learn the details of how to use will-change, its benefits and downsides, in An Introduction to the CSS will-change Property by Nick Salloum.

#3 Replace setTimeOut/setInterval with requestAnimationFrame

JavaScript animations have commonly been coded using either setInterval() or setTimeout().

The code would look something like this:

var timer;
function animateElement() {
  timer = setInterval( function() {
    // animation code goes here
  } , 2000 );
}

// To stop the animation, use clearInterval
function stopAnimation() {
  clearInterval(timer);
}

Although this works, the risk of jank is high, because the callback function runs at some point in the frame, perhaps at the very end, which can result in one or more frames being missed. Today, you can use a native JavaScript method which is tailored for smooth web animation (DOM animation, canvas, etc.), called requestAnimationFrame().

requestAnimationFrame() executes your animation code at the most appropriate time for the browser, usually at the beginning of the frame.

Your code could look something like this:

function makeChange( time ) {
  // Animation logic here

  // Call requestAnimationFrame recursively inside the callback function
  requestAnimationFrame( makeChange ):
}

// Call requestAnimationFrame again outside the callback function
requestAnimationFrame( makeChange );

Performance with requestAnimationFrame by Tim Evko here on SitePoint offers a great video introduction to coding with requestAnimationFrame().

#4 Decouple Events from Animations in Your Code

At 60 frames per second, the browser has 16.67ms to do its job on each frame. That’s not a lot of time, so keeping your code lean could make a difference to the smoothness of your animations.

Decoupling the code for handling events like scrolling, resizing, mouse events, etc., from the code that handles screen updates using requestAnimationFrame() is a great way to optimize your animation code for performance.

For a deep discussion of this optimization tip and related sample code, check out Leaner, Meaner, Faster Animations with requestAnimationFrame by Paul Lewis.

#5 Avoid Long-running JavaScript Code

Browsers use the main thread to run JavaScript, together with other tasks like style calculations, layout and paint operations. Long-running JavaScript code could negatively impact on these tasks, which could lead to frames being skipped and janky animations as a consequence. Therefore, simplifying your code could certainly be a good way to ensure your animations run smoothly.

For complex JavaScript operations that don’t require access to the DOM, consider using Web Workers. The worker thread performs its tasks without impacting on the user interface.

#6 Leverage the Browser’s DevTools to Keep Performance Issues in Check

Your browser’s developer tools provide a way to monitor how hard your browser is working to run your JavaScript code, or that of a third-party library. They also provide useful information about frame rates and much more.

You can access the Chrome DevTools by right-clicking on your web page and selecting Inspect inside the context menu. For example, recording your web page using the Performance tools will give you an insight into the performance bottlenecks on that page:

Performance tab in Chrome dev tools

Click the record button, then stop the recording after a few seconds:

Once the animation is stopped

At this point, you should have tons of data to help you analyze your page’s performance:

Data from the Performance dev tools in Chrome

This Chrome DevTools Guide will help you get the most out of DevTools for analyzing performance and lots of other kinds of data in your Chrome browser. If Chrome isn’t your browser of choice, it’s no big deal, as most modern browsers nowadays ship with super powerful DevTools that you can leverage to optimize your code.

#7 Use an Off-screen Canvas for Complex Drawing Operations

This tip relates specifically to optimizing code for HTML5 Canvas.

If your frames involve complex drawing operations, a good idea would be to create an off-screen canvas where you perform all the drawing operations once or just when a change occurs, and then on each frame just draw the off-screen canvas.

You can find the details and code samples relative to this tip and lots more in the Optimizing Canvas article on MDN.

Conclusion

Optimizing code for performance is a necessary task if you don’t want to fail users’ expectations on the web today, but it’s by no means always easy or straightforward. There might be several reasons why your animations aren’t performing well, but if you try out the tips I listed above, you’ll go a long way towards avoiding the most common animation performance pitfalls, thereby improving the user experience of your website or app.

Frequently Asked Questions (FAQs) on Jank-Free JavaScript Animations

What is the concept of ‘jank’ in JavaScript animations?

Jank’ refers to any stuttering, juddering, or just plain halting that users see when a site or app isn’t keeping up with the refresh rate. In JavaScript animations, jank can occur when the frame rate drops below the standard 60 frames per second. This can lead to a less smooth and visually appealing animation, which can negatively impact the user experience.

How can I ensure smooth JavaScript animations?

Ensuring smooth JavaScript animations involves optimizing your code to maintain a steady 60 frames per second. This can be achieved by using the requestAnimationFrame method, which allows the browser to optimize the animation. You can also use CSS transitions or animations for simpler animations, as they are typically more performant than JavaScript. Additionally, avoid layout thrashing by batching DOM read and write operations together.

What is the role of ‘requestAnimationFrame’ in JavaScript animations?

The ‘requestAnimationFrame’ method in JavaScript is a crucial tool for creating smooth animations. It tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. This method allows the browser to optimize the animation, leading to smoother and more efficient animations.

How can CSS transitions or animations be more performant than JavaScript?

CSS transitions and animations can be more performant than JavaScript because they are handled by the browser’s compositor thread, separate from the main JavaScript thread. This means they can run smoothly even when the main thread is busy with other tasks. Additionally, certain properties can be animated in CSS without causing a repaint, making them particularly efficient.

What is layout thrashing and how can it be avoided in JavaScript animations?

Layout thrashing occurs when JavaScript repeatedly reads and writes to the DOM, causing the browser to recalculate the layout multiple times and leading to inefficient, janky animations. This can be avoided by batching DOM read and write operations together. For example, instead of interspersing reads and writes, you can do all your reads first and then do all your writes.

How can I use ‘will-change’ property to optimize JavaScript animations?

The ‘will-change’ property in CSS allows you to inform the browser ahead of time about what kinds of changes you are likely to make to an element, so that it can set up appropriate optimizations before they’re needed. This can significantly improve the performance of animations. However, it should be used sparingly, as overuse can cause the browser to spend too much time on optimizations.

What is the significance of ‘transform’ and ‘opacity’ properties in JavaScript animations?

The ‘transform’ and ‘opacity’ properties in CSS are particularly efficient for animations. This is because changes to these properties can be handled by the browser’s compositor thread, without requiring a layout or paint. This means they can run smoothly even when the main JavaScript thread is busy.

How can I use ‘Web Workers’ to improve the performance of JavaScript animations?

Web Workers’ in JavaScript allow you to run scripts in the background, separate from the main execution thread. This means they can handle computationally intensive tasks without blocking the main thread and causing jank. However, they have some limitations, such as not being able to access the DOM or certain web APIs.

What is ‘off-main-thread’ animation and how can it benefit JavaScript animations?

Off-main-thread’ animation refers to running animations on a separate thread from the main JavaScript thread. This can significantly improve the performance of animations, as it allows them to run smoothly even when the main thread is busy. This can be achieved using tools like CSS animations, Web Workers, or the Web Animations API.

How can I use the ‘Web Animations API’ to create efficient JavaScript animations?

The ‘Web Animations API’ provides a way to create animations using JavaScript that are as performant as CSS animations. It allows you to control and manipulate animations directly from JavaScript, giving you more flexibility than CSS animations. However, it’s still an experimental technology and is not fully supported in all browsers.

Maria Antonietta PernaMaria Antonietta Perna
View Author

Maria Antonietta Perna is a teacher and technical writer. She enjoys tinkering with cool CSS standards and is curious about teaching approaches to front-end code. When not coding or writing for the web, she enjoys reading philosophy books, taking long walks, and appreciating good food.

animationBrunoSjankjavascriptjavascript optimizationjsoptimizationperformanceperformance-hubrequestAnimationFrameunderstanding-performance
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week