Skip to content

Instantly share code, notes, and snippets.

@Warry
Created December 11, 2012 00:11
Show Gist options
  • Save Warry/4254579 to your computer and use it in GitHub Desktop.
Save Warry/4254579 to your computer and use it in GitHub Desktop.
How to make faster scroll effects?

How to make faster scroll effects?

  • Avoid too many reflows (the browser to recalculate everything)
  • Use advanced CSS3 for graphic card rendering
  • Precalculate sizes and positions

Beware of reflows

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.

Graphic rendering

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.

Save calculations

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

The last HTML file is a bad exemple, showing the difference with window.onscroll and without CSS 3D.

<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Faster scroll effect</title>
<link rel="stylesheet" href="fse.css">
</head>
<body>
<div id="wrapper">
<section>
<article>
<h1>SCROLL DOWN</h1>
</article>
</section>
<section class="stick">
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
<section class="stick">
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
<section>
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
</div>
<script src="fse.js"></script>
</body>
</html>
html, body {
height: 100%;
font: 19px "Helvetica Neue", "Helvetica", sans-serif;
color: #333;
}
section {
background: white;
position: fixed;
display:block;
top: 0;
left: 0;
width: 100%;
min-height: 100%;
overflow: hidden;
z-index: 100;
transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-webkit-transform: translate3d(0,0,0);
}
section.stick {
z-index: 10;
}
/* Decoration */
section:nth-child(1){
background: url(http://i.images.cdn.fotopedia.com/alibradshaw-bs7HFo22Ff4-hd/New_York_City/New_York_City.jpg);
/* Ali Bradshaw - http://www.fotopedia.com/wiki/New_York_City#!/items/alibradshaw-bs7HFo22Ff4 */
background-size: cover;
}
section:nth-child(2){
background: #f5f5f5;
}
section:nth-child(4){
background: #fff;
}
section:nth-child(3){
background: url(http://i.images.cdn.fotopedia.com/fransimo-onrEHtg2404-hd/New_York_City/Rector_Street.jpg);
/* Fran Simó - http://www.fotopedia.com/wiki/New_York_City#!/items/fransimo-onrEHtg2404 */
background-size: cover;
color: #fff;
text-shadow: 0 0 3px #000;
text-align: right;
}
article {
width: 600px;
margin: 60px auto;
}
section:nth-child(3) article {
float: right;
margin: 60px;
}
h1, h2, h3 {
font-family: "HelveticaNeue-CondensedBold", "Helvetica Neue", "Helvetica", sans-serif;
font-weight: bold;
font-stretch: condensed;
}
h1 {
text-align: center;
font-size: 60px;
color: #fff;
}
h1:before {
content: "⬇"; /* ↓ ⇓ */
}
/*
* Faster Scroll Effect
* Version: 0.1
* Copyright 2012
* MIT Licence
*/
(function(){
// Detect css transform
var cssTransform = (function(){
var prefixes = 'transform webkitTransform mozTransform oTransform msTransform'.split(' ')
, el = document.createElement('div')
, cssTransform
, i = 0
while( cssTransform === undefined ){
cssTransform = document.createElement('div').style[prefixes[i]] != undefined ? prefixes[i] : undefined
i++
}
return cssTransform
})()
// Detect request animation frame
var scroll = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000/60) }
// Vars
, has3d = document.body.style.transform
, lastPosition = -1
, wHeight = window.innerHeight
, wrapper = document.getElementById("wrapper")
, elements = document.getElementsByTagName("section")
, size = elements.length
, matrix = []
// Pre calculate sizes to get better perfs
function sizes(){
lastPosition = -1 // Force a recalculation
wHeight = window.innerHeight
var i = 0
for (i =0; i<size; i++){
matrix[i] = matrix[i] || { el: elements[i] }
// Reinit
matrix[i].el.style.display = "block"
matrix[i].height = matrix[i].el.offsetHeight
matrix[i].start = matrix[i-1] ? matrix[i-1].stop : 0
matrix[i].stop = matrix[i-1] ? matrix[i-1].stop + matrix[i].height : matrix[i].height
matrix[i].isScroll = matrix[i].el.className.indexOf("stick") < 0
// If it's sticked but higher than the screen...
if (matrix[i].height - wHeight > 0) matrix[i].gap = matrix[i].height - wHeight
// Let's find a index
matrix[i].el.style.zIndex = !matrix[i].isScroll ? 10 - i : 100 - i
}
wrapper.style.height = matrix[i-1].stop + "px"
}
window.onresize = sizes
function setTop(m, t){
if (cssTransform)
m.el.style[cssTransform] = "translate3d(0, "+ t +"px,0)"
else
m.el.style["top"] = t
}
function loop(){
// Avoid calculations if not needed
if (lastPosition == window.pageYOffset) {
scroll(loop)
return false
} else lastPosition = window.pageYOffset
var i = 0
for (i =0; i<size; i++){
// Is it visible right now?
if (lastPosition >= matrix[i].start - wHeight && lastPosition <= matrix[i].stop){
matrix[i].el.style.display = "block"
if (
// Is it scrolling?
(matrix[i].isScroll) ||
// Or is it stick, but higher than window?
(!matrix[i].isScroll && matrix[i].gap && lastPosition >= matrix[i].start)
)
setTop(matrix[i], matrix[i].start - lastPosition)
} else {
matrix[i].el.style.display = "none"
}
}
scroll(loop)
}
// Let's go
sizes()
loop()
})();
<!--
BAD EXEMPLE WITH window.onscroll
BAD EXEMPLE WITH window.onscroll
BAD EXEMPLE WITH window.onscroll
-->
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Slow scroll effect</title>
<link rel="stylesheet" href="fse.css">
</head>
<body>
<div id="wrapper">
<section>
<article>
<h1>SCROLL DOWN</h1>
</article>
</section>
<section class="stick">
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
<section class="stick">
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
<section>
<article>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</article>
</section>
</div>
<script>
// BAD CODE !
// This is the counter example
var lastPosition = -1
, wHeight = window.innerHeight
, wrapper = document.getElementById("wrapper")
, elements = document.getElementsByTagName("section")
, size = elements.length
, matrix = []
// Pre calculate sizes to get better perfs
function sizes(){
wHeight = window.innerHeight
var i = 0
for (i =0; i<size; i++){
matrix[i] = matrix[i] || { el: elements[i] }
// Reinit
matrix[i].el.style.display = "block"
lastPosition = -1
matrix[i].height = matrix[i].el.offsetHeight
matrix[i].start = matrix[i-1] ? matrix[i-1].stop : 0
matrix[i].stop = matrix[i-1] ? matrix[i-1].stop + matrix[i].height : matrix[i].height
matrix[i].isScroll = matrix[i].el.className.indexOf("stick") < 0
// If it's sticked but higher than the screen...
if (matrix[i].height - wHeight > 0) matrix[i].gap = matrix[i].height - wHeight
// Let's find a index
matrix[i].el.style.zIndex = !matrix[i].isScroll ? 10 - i : 100 - i
}
wrapper.style.height = matrix[i-1].stop + "px"
}
window.onresize = sizes
function setTop(m, t){
console.log(t)
m.el.style.top = t + "px"
}
function loop(){
lastPosition = window.pageYOffset
var i = 0
for (i =0; i<size; i++){
// Is it visible right now?
if (lastPosition >= matrix[i].start - wHeight && lastPosition <= matrix[i].stop){
matrix[i].el.style.display = "block"
if (
// Is it scrolling?
(matrix[i].isScroll) ||
// Or is it stick, but higher than window?
(!matrix[i].isScroll && matrix[i].gap && lastPosition >= matrix[i].start)
)
setTop(matrix[i], matrix[i].start - lastPosition)
} else {
matrix[i].el.style.display = "none"
}
}
}
// Let's go
sizes()
window.onscroll = loop
</script>
<style type="text/css">
section {
transform: none;
-moz-transform: none;
-webkit-transform: none;
}
</style>
</body>
</html>
@guci0
Copy link

guci0 commented Nov 9, 2017

@2kool2 – nice job, I'm testing – please click, down arrow once...

@geosigno
Copy link

geosigno commented Feb 28, 2018

Hi,

Thank you very much for this, however I am facing an issue...

I am using your method in a jQuery plugin and I can't find a way to call a private method in the requestAnimation callback.

`

var scroll = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || 
 window.msRequestAnimationFrame || window.oRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000/60)

var lastPosition = -1

function Plugin ( element, options ) {
    this.init();
}

$.extend(Plugin.prototype, {

    init: function () {

        var plugin = this;

        plugin.proceedElement();
       
    },

    animate: function() {
        ///
    },


    proceedElement: function() {

        var plugin = this;

        if (lastPosition == window.pageYOffset) {

            scroll(plugin.proceedElement);

            return false;

        } else {

            lastPosition = window.pageYOffset;

            plugin.animate();

            scroll(plugin.proceedElement);

        }

    },

});`

I have an error in the console saying "Uncaught TypeError: Cannot read property 'proceedElement' of null".

I am pretty sure it is a quick fix for someone who knows...

@MrEichi
Copy link

MrEichi commented Mar 13, 2019

// Avoid calculations if not needed if (lastPosition == window.pageYOffset) { scroll(loop) return false } else lastPosition = window.pageYOffset
If I am not mistaken, this triggers a layout/reflow. So you are basically layouting the whole page at each frame, even if the user did not scroll. That does not sound like an optimization at all to me. And if I see it correctly, you are even doing it twice 🤔

@tylerchilds
Copy link

@Download @microcipcip @MrEichi

Just came across this today for something I was poking around on. I abstracted it out into this gist as createScrollManager. This accounts for not calling requestAnimationFrame loop when the user hasn't moved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment