Hooking Up to the window.onscroll Event Without Killing Your Performance
This week was my one-month anniversary at Lemonly, and in that month, I’ve used more onscroll event hooks than I have in the last 15 years of development, and for good reason. It’s a great way to add flair, track progress, or get parallax-y. If you don’t do it right, it’ll crush your site’s performance and irritate your users. So what’s the best way to hook up to the window.onscroll event and still maintain a reasonable frame-per-second rate when scrolling?
window.onscroll and setInterval()
window.onscroll = doThisStuffOnScroll; function doThisStuffOnScroll() { console.log('You scrolled'); }
The real issue with this code, and with window.onscroll in general, is it fires every time you scroll one pixel (or one scroll unit, whatever that is on your OS). If your user scrolls too fast for your events, the FPS drops and the scroll loses it’s smoothness, especially if your doThisStuffOnScroll() contains elaborate logic or animations. The answer is to force the browser to spread out how often it fires the functions you’ve hooked up to the window.onscroll event.
var didScroll = false; window.onscroll = doThisStuffOnScroll; function doThisStuffOnScroll() { didScroll = true; } setInterval(function() { if(didScroll) { didScroll = false; console.log('You scrolled'); } }, 100);
What this code is doing:
- It creates a variable, didScroll, that defaults to false. This variable will indicate to the setInterval function if the user has scrolled.
- The function doThisStuffOnScroll changes didScroll to true if the user scrolls.
- Inside the setInterval, didScroll gets set back to false, which effectively resets the system and makes it ready to watch for the next time the user scrolls.
- The function inside setInterval checks the value of didScroll every 100ms, which means the functionality that occurs on scrolling occurs only once every 100ms, a vast improvement over the default.
There are far more complicated methods to accomplish what I’m doing here, and some of them are technically better. But for what I’m doing, I value the simplicity of this method that allows me to implement it quickly when I need it.
It can also be adapted to be used for most of the other DOM events. I’ve used it for onmouseover/out, click, and resize.
Examples of the use of the tech above: Responsive Infographics, Autodesk 360
Have a better way to do this? I’d love to hear about it. Let me know in the comments or tweet me at @joshbroton.