Yaogang Lian

-webkit-overflow-scrolling:touch and screen flickering

I ran into a sneaky screen flickering issue in the last few days while finishing up a webapp. The screen flickers a bit when changing pages, as seen in the video below.




You might want to pause the video and view it frame by frame to see what’s happening during the page swap. Note that I intentionally did not apply any view transition or animation, but simply remove the old page, then add the new page to the DOM. Here is the code that does the page swap:

1
2
3
4
5
6
7
8
showPage: (p) ->
# Remove the previous page
@currentPage?.remove()
# Show the new page
@$('#rootview .page-container').empty().append(p.render().el)
@currentPage = p


If you watch the video frame by frame, you may notice that the screen flickering happens because the old page disappears first, then after a tiny delay (~50ms), the new page appears. Ideally we want to see the old page disappearing and the new page appearing at the exact same time.

So what is causing the tiny 50ms delay? After spending hours profiling the app, I finally found the root cause, and it’s a bit surprising. It turns out the flickering was caused by setting “-webkit-overflow-scrolling: touch” on the page element. Setting this on the page element enables native style momentum scrolling on iOS devices. However, this works by promoting the page element to its own layer, similar to what -webkit-transform: translateZ(0); does. When you subsequently remove the page element and create a new one, this layer is destroyed and created anew. That caused the tiny delay which makes the screen flicker.

The fix is to apply “-webkit-overflow-scrolling: touch” on the page container instead. The page container always stays in the DOM, so when changing pages, we no longer destroy and recreate layers. The final result can be seen in the video below.

Yaogang Lian

An iOS, Mac and web developer. Focusing on building productivity and educational apps.