- Avoid too many reflows (the browser to recalculate everything)
- Use advanced CSS3 for graphic card rendering
- Precalculate sizes and positions
The reflow appens as many times as there are frames per seconds. It recalculate all positions that change in order to diplay them. Basically, when you scroll you execute a function where you move things between two reflows. But there are functions that triggers reflows such as jQuery offset, scroll... So there are two things to take care about when you dynamically change objects in javascript to avoid too many reflows:
- use window.pageYOffset to get the scroll position
- prefer requestAnimationFrame than onScroll event.
Why is requestAnimationFrame (really) faster than the scroll event? Actually the scroll event popups whenever it wants, even if you haven't finished calculating the previous position, or between two reflows... While the requestAnimationFrame can only popup if the previous frame was calculated. So you save reflows out of your loop function, and you manage to never overlap two calculations.
// Detect request animation frame
var scroll = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// IE Fallback, you can even fallback to onscroll
function(callback){ window.setTimeout(callback, 1000/60) };
function loop(){
var top = window.pageYOffset;
// Where the magic goes
// ...
// Recall the loop
scroll( loop )
}
// Call the loop for the first time
loop();
This does half of the work.
On modern webkit, if you use 3D css then your elements are both cached as bitmap (one object to render for the element and children) and rendered by the GPU. This works for scroll effects, but actually also for every kind of animations and transitions. It works really (really) well on the mobile too.
transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-webkit-transform: translate3d(0,0,0);
Be carefull with position:fixed
inside a 3D element, they will appear like they were absolute.
Like I said before, the browser is calculating a lot of things when you modify the DOM. A smooth animation should have between 30 and 60 frames (and reflows) per second. If you ask too much calculation at each frame then your animation will be slower. jQuery doesn't help much for that (big objects, no cache).
Since the requestAnimationFrame works all the time and not only when you scroll, you better tells your browser that it has nothing to calculate if you haven't scrolled:
var lastPosition = -1;
function loop(){
// Avoid calculations if not needed
if (lastPosition == window.pageYOffset) {
scroll(loop);
return false;
} else lastPosition = window.pageYOffset;
//... calculations
scroll( loop );
}
I suggest you to have a look at the whole attached piece of code, that is structured like that:
- Detect advanced features
- Define all variables
- Precalculation function (called on load and resize)
- Loop function (called up to 60 times per second)
- Try to skip calculations
- Find elements that will change
- Modify the DOM