Improving ionic page transitions



I’ve been working for the past few days on improving the performance of page transitions for ionic. I haven’t reached the results that I want yet, but here’s everything I was able to understand, hopefully we can combine everything we have in order to improve page transitions.

  1. First of all, “transitions lagging” can be a subjective topic. When I asked my fellow developers to investigate slow transitions, some of them replied that they’re not slow… although I could see them lagging. In order to make this an objective topic, I am using the same strategy Paul Irish (from Chrome) uses to debug bottlenecks in Javascript and CSS3. Chrome developer tools => Timeline.
    After you record a page transition, if you see bars that go on top of the 60fps and reach maybe 30fps this means that we have a slow transition. (Why? more on that in the conclusion)

  2. In order to eliminate external factors, I stopped working on my app and downloaded an official ionic starter app: side menu.
    I was still seeing bars/spikes going on top of the 60fps limit. Which suggestions that the issue does not depend on the following:

  • heavy markup
  • filters (they are a bottleneck in general but not in this scenario because we haven’t used them yet)
  • route controller (the routes that I was testing didn’t even have a controller)
  • custom user code (although this could make it worse)
  1. I also disabled page transitions (globally and via the nav-transition=“none”) and I was still getting almost the same results!
    Here’s where I realized that the bottleneck is not the actual CSS transition, but everything happening before (more on that in the conclusion)


  1. All my tests were done on a previously cached route:
  • enable route caching
  • visit page
  • go back
  • start profiling
  • click on link that opens next route (which is already cached)
  • stop profiling
  1. If you are seeing good results, I usually try simulating poor mobile performance on my desktop by making the app’s viewport much larger than a mobile display. And if you want to test the actual performance, you can ionic run android your app and connect using Chrome’s webview debug (available on android >= 4.4.4).

  2. These are the steps that you need to follow if you want to see the FPS counter and Flame chart:

  • FPS:
    Chrome developer tools > Timeline > Select: Causes, JS Profiler, Memory, Paint > Record > open cached view > Stop
  • Flame Chart:
    Chrome developer tools > Profiles > Collect Javascript CPU Profile > Start > open cached view > Stop > Select Chart from the top dropdown
  1. Timeline is also showing the following for Layout painting: Forced synchronous layout is a possible performance bottleneck.

  2. You can argue that ~68ms is fine when opening a cached view. But note that as soon as you add any HTML to the route that you’re opening, this number will get much bigger.

Here’s the conclusion that I came up with, feel free to correct me or to improve upon it:
Because JavaScript is single threaded, heavy javascript computation is happening before the page transition which is causing the transition to lag. There is to issue with CSS transition at all (as we can see in the timeline).


[Flame Chart]

Let me know what you think




Watching the topic for answers!



I’ve been thinking the same thing. Some initial feedback from my app was some of the transitions were quite slow, the user would even tap a few times because it seemed like nothing was happening.

The worst offender was going to a chat page which loaded the chat history out of the sqlite database from a ui-router resolve.
I moved the loading from the ui-router to the $ionicView.enter event. While the total time is a little bit longer as the loading starts later, the user experience is much better having an instant smooth animation.


Can you show me a sample code for the $ionicView.enter, my colleagues said that they had issues with this and they couldn’t get it to work


It’s just like this in a Controller:

$scope.$on('$ionicView.enter', function () {
    ChatService.loadChat(chatId).then((messages) => {...})