I am developing a single-page Javascript application that runs on desktop browsers and also on mobile devices via Cordova/Phonegap.
I have a slide-out menu that is implemented using CSS transitions. I noticed that it works well on desktop browsers and android. However, on IOS there are serious performance issues. The transition does not appear to start on time, but once it starts the rendering and duration looks fine. The time between starting the transition and the transitionend event is way higher on IOS than other platforms. For example, the duration of the transition is 300ms but I'm not getting the transitionend event for 1500ms. On all other platforms, I get the transitionend event in 325-350ms.
Transitionend Event:
- Expected: 350ms
- Actual: 1500ms
Platforms:
- Cordova 6.3.1
- Xcode 8.1 GM Seed
- IOS 10.1
Here is the CSS for the menu div. To slide-out the menu, I add the 'open' class. To close the menu, I remove the 'open' class. I've tried transitioning on the 'left' property and 'transform' property, but the results are identical.
/* Nav Menu */
#navmenu {
position: absolute;
top: 0;
width: 90%;
max-width: 400px;
z-index: 20;
height: auto;
background-color: white;
/*
-webkit-transform: translate3d(-100%,0,0);
-moz-transform: translate3d(-100%,0,0);
-ms-transform: translate3d(-100%,0,0);
transform: translate3d(-100%,0,0);
-webkit-transition: -webkit-transform 300ms ease;
-moz-transition: -moz-transform 300ms ease;
-ms-transition: -ms-transform 300ms ease;
-o-transition: -o-transform 300ms ease;
transition: transform 300ms ease;
*/
left: -100%;
-webkit-transition: left 300ms ease;
-moz-transition: left 300ms ease;
-ms-transition: left 300ms ease;
-o-transition: left 300ms ease;
transition: left 300ms ease;
}
#navmenu.open {
/*
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-transition: -webkit-transform 300ms ease;
-moz-transition: -moz-transform 300ms ease;
-ms-transition: -ms-transform 300ms ease;
-o-transition: -o-transform 300ms ease;
transition: transform 300ms ease;
*/
left: 0;
-webkit-transition: left 300ms ease;
-moz-transition: left 300ms ease;
-ms-transition: left 300ms ease;
-o-transition: left 300ms ease;
transition: left 300ms ease;
}
Question: What might be causing the delay in starting the transition, only on IOS platforms? Are there any known solutions to circumvent the problem or speed things up? I have other transitions in the app that take over 5s to start, making the app unusable. I'm hoping the menu solution will apply throughout the app. Thanks for any help or ideas you can provide.
Here is the instrumented Javascript code that I use to open/close the menu...
utilities.addEventListeners(navMenuButtonDiv, function () {
var start = Date.now();
var menuDiv = navMenu.getDiv();
if (menuDiv.classList.contains('open')) {
menuDiv.classList.remove('open');
} else {
menuDiv.classList.add('open');
}
var handler = function (event) {
console.log('Transition: ' + (Date.now() - start));
menuDiv.removeEventListener('webkitTransitionEnd', handler, true);
};
menuDiv.addEventListener('webkitTransitionEnd', handler, true);
};
I am developing a single-page Javascript application that runs on desktop browsers and also on mobile devices via Cordova/Phonegap.
I have a slide-out menu that is implemented using CSS transitions. I noticed that it works well on desktop browsers and android. However, on IOS there are serious performance issues. The transition does not appear to start on time, but once it starts the rendering and duration looks fine. The time between starting the transition and the transitionend event is way higher on IOS than other platforms. For example, the duration of the transition is 300ms but I'm not getting the transitionend event for 1500ms. On all other platforms, I get the transitionend event in 325-350ms.
Transitionend Event:
- Expected: 350ms
- Actual: 1500ms
Platforms:
- Cordova 6.3.1
- Xcode 8.1 GM Seed
- IOS 10.1
Here is the CSS for the menu div. To slide-out the menu, I add the 'open' class. To close the menu, I remove the 'open' class. I've tried transitioning on the 'left' property and 'transform' property, but the results are identical.
/* Nav Menu */
#navmenu {
position: absolute;
top: 0;
width: 90%;
max-width: 400px;
z-index: 20;
height: auto;
background-color: white;
/*
-webkit-transform: translate3d(-100%,0,0);
-moz-transform: translate3d(-100%,0,0);
-ms-transform: translate3d(-100%,0,0);
transform: translate3d(-100%,0,0);
-webkit-transition: -webkit-transform 300ms ease;
-moz-transition: -moz-transform 300ms ease;
-ms-transition: -ms-transform 300ms ease;
-o-transition: -o-transform 300ms ease;
transition: transform 300ms ease;
*/
left: -100%;
-webkit-transition: left 300ms ease;
-moz-transition: left 300ms ease;
-ms-transition: left 300ms ease;
-o-transition: left 300ms ease;
transition: left 300ms ease;
}
#navmenu.open {
/*
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-transition: -webkit-transform 300ms ease;
-moz-transition: -moz-transform 300ms ease;
-ms-transition: -ms-transform 300ms ease;
-o-transition: -o-transform 300ms ease;
transition: transform 300ms ease;
*/
left: 0;
-webkit-transition: left 300ms ease;
-moz-transition: left 300ms ease;
-ms-transition: left 300ms ease;
-o-transition: left 300ms ease;
transition: left 300ms ease;
}
Question: What might be causing the delay in starting the transition, only on IOS platforms? Are there any known solutions to circumvent the problem or speed things up? I have other transitions in the app that take over 5s to start, making the app unusable. I'm hoping the menu solution will apply throughout the app. Thanks for any help or ideas you can provide.
Here is the instrumented Javascript code that I use to open/close the menu...
utilities.addEventListeners(navMenuButtonDiv, function () {
var start = Date.now();
var menuDiv = navMenu.getDiv();
if (menuDiv.classList.contains('open')) {
menuDiv.classList.remove('open');
} else {
menuDiv.classList.add('open');
}
var handler = function (event) {
console.log('Transition: ' + (Date.now() - start));
menuDiv.removeEventListener('webkitTransitionEnd', handler, true);
};
menuDiv.addEventListener('webkitTransitionEnd', handler, true);
};
Share
Improve this question
edited Oct 28, 2016 at 3:29
jmelvin
asked Oct 28, 2016 at 3:12
jmelvinjmelvin
6571 gold badge10 silver badges17 bronze badges
1
- UPDATE: The latest update to IOS (10.1.1) appears to have exacerbated the problem quite considerably. Even after porting top/left to transitioning on transforms, it is still a problem. Any transition on iPhone5 starts very late, sometimes well more than 5 seconds after button click/touch. Performance is somewhat better on iPhone6, leading me to believe it's a memory issue and perhaps a bit of planned obsolescence to get people off old iPhones. Try the app on an older iPhone for a demo at sizzlescene.. – jmelvin Commented Nov 23, 2016 at 15:18
1 Answer
Reset to default 6When moving elements around the screen, you want to maximize performance. Instead of transitioning the left
property, you're better off using translation. Using translation, the device will use its GPU to render the onscreen change, on a layer above the DOM. This will result in a smoother, more performant transition.
Have a look at this example. Besides using a transform
instead of changing the left
property, notice that I removed a bit of redundancy. You don't need to redeclare the transition on the active state.
var open = document.getElementById("open"),
close = document.getElementById("close"),
nav = document.getElementById("navmenu");
open.addEventListener("click", function() {
nav.classList.add("open");
});
close.addEventListener("click", function() {
nav.classList.remove("open");
});
#navmenu {
position: absolute;
top: 0;
left: 0;
width: 90%;
max-width: 400px;
z-index: 20;
height: auto;
background-color: white;
transform: translate3d(-100%, 0, 0);
-webkit-transition: transform 300ms ease-in-out;
-moz-transition: transform 300ms ease-in-out;
-ms-transition: transform 300ms ease-in-out;
-o-transition: transform 300ms ease-in-out;
transition: transform 300ms ease-in-out;
}
#navmenu.open {
transform: translate3d(0, 0, 0);
}
button {
margin-top: 100px;
}
<div id="navmenu">stuff in here</div>
<button id="open">Open Menu</button>
<button id="close">Close Menu</button>