60 FPS JavaScript swiping on mobile

A mistake that is worth 30 extra frames per second

Etienne Lemay
Jun 23, 2017 · 3 min read

Following my Cross-platform email client with nothing but HTML article, we’ve been told by many people that they’d love to hear more about some tricks that make our app feel so native and fast.

Take our conversation list for example and the steps we took to get a 60 FPS on (almost) every mobile device. For the simplicity of this article, we’ll just assume that we have a list (ul) of items (li). Also note that no transition or animation are involved when I’m talking about swiping; I’m just referring to the items following the touch as you move your finger.

li are normally positioned. Upon swiping, each of the targeted li (hello Multi-Swipe™) has its transform: translateX() updated. Chances are that if you test on a very powerful and recent mobile or Chrome with device toolbar enabled, it’ll be as good as native. On my iPhone 6, we thought it felt pretty good for a JS swipe. Only then did we buy a Google Pixel to develop the Android version and realized how much more responsive the swiping was on that device. My phone not being that old, we knew there was some improvements that could be done.

I didn’t plan on talking about this one and start the initial version above with translate3d, but truth is I did use translateX at first. It was my understanding that nowadays translateX is just as hardware-accelerated as its 3d equivalent. However it felt a little bit more fluid withtranslate3d, especially on mobile. 🙌🏼

Image for post
Image for post

An issue on my phone that we didn’t feel on the Pixel was that there would be some delay between the moment the touch move began and the first rendering of the swiped elements. The UI was frozen during the first 10px and then the items jumped to the position they were supposed to be. 🤢

We figured it was the hardware accelerating rocket booting up. 🚀
So we put the li in an already “accelerated” state by absolutely positioning them and tranlate3d to their position. It worked! No more delay on my phone at the beginning of the gesture. 🙌🏼

Image for post
Image for post

p.s. I know about the infamous backface-visibility: hidden trick, but in our case it didn’t seem to change anything.

Now that the items are translated on the y-axis, all we need to do is translate the x when swiping while keeping the y and we’ll be done!

Image for post
Image for post
What I thought I was doing…

But here comes “the mistake”. I somehow mixed some React refs and ended up translating the underlying div instead.

Image for post
Image for post
What I did instead, by mistake.

We could instantly feel the difference and knew we had finally reached that native feeling that we were looking for. See the difference for yourself:

Translating the same element on both axis

If you think this is video recording lag, wait until you see the next one.

Translating different element per axis

If you liked this trick, give us a follow. Who knows, we might make more mistakes like this one. 🤖

Missive App

The one app for team email and chat

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store