8

I'm trying to build a parallax site, which will move few elements while scrolling the site. But instead of using a scroll event listener I'm using requestAnimationFrame, after reading this post by Paul Irish, and this video which said that scroll listener is a bit buggy. My questions are:

  1. It looks quite smooth in Chrome, but it's flickering badly in Firefox. Did I do something wrong here?
  2. Does my code actually taking up more resources than using normal scroll event listener? I can hear my laptop fan blazing every time I'm playing with this code.

My file is located at http://www.socialbuzz.com.au/index.html, and please scroll to the bottom of the page to see the element that's being manipulated from javascript.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
Zendy
  • 1,664
  • 1
  • 17
  • 24
  • 1
    You should add the relevant code which uses `requestAnimationFrame` to your question, for the future readers after you update your site. – Kevin Reid May 15 '12 at 14:47
  • Also, is [this](http://paulirish.com/2011/requestanimationframe-for-smart-animating/) the article about `requestAnimationFrame` you meant? – Kevin Reid May 15 '12 at 14:48

3 Answers3

6

You should have a the scroll event trigger a requestAnimationFrame loop. Do not have requestAnimationFrame triggered by the scroll event itself. You should have something like a var scrolling = true; While this is happening run your requestAnimationFrame loop which references event data from the scroll event. You'll need to debounce the scroll event to turn to loop off once you are finished, it's a chore but the results are worth it. Hope this helps.

tencircles
  • 211
  • 1
  • 6
  • ok, so I have one `requestAnimationFrame` object, and if the browser is in view, I run `requestAnimationFrame` loop. Once it's not in view, then I stop the loop? – Zendy May 16 '12 at 05:47
  • From looking at your code your rAF is inside of a jQuery each function so you're actually calling it 4 times every frame. My original point was mainly that you can keep your scroll listener. The only thing your scroll listener needs to do is get the numbers you need (scrollTop or whatever) and let requestAnimationFrame know that it needs to start running (via a scrolling variable). Once the user has stopped scrolling then you set the variable to false. Your loop should look something like this. `(function animloop(){ if(scrolling){ requestAnimFrame(animloop); render(); })();` – tencircles May 17 '12 at 03:42
  • ok..and how do you stop the rAF from running? should I do like `var raf1 = requestAnimFrame(animloop);`, then later on when I want to stop it I do `window.cancelAnimFrame(raf1)`? – Zendy May 18 '12 at 02:42
  • I do this by debouncing basically. So when a scroll event is fired it just calls a function that sets var scrolling = true and calls animLoop(). To debounce it set a timeout each time the scroll event is called, if it exists when the function is called, clear it. On completion the callback of the setTimeout should turn off your loop. This way your scroll event just turns on the animLoop function and it will shut off after x milliseconds (whatever you have your debounce setTimeout to). Inside your animloop it should look something like if(scrolling) rAF(animLoop); renderAnimation(); – tencircles Jun 08 '12 at 21:29
4

You are not performing an animation; that is, you are not modifying your graphics continuously without user interaction. Your manipulation of the page happens only when the user scrolls and does not continue after the user stops scrolling. Therefore, there is no benefit to using requestAnimationFrame, and you should stick to a simple event handler.

The purpose of requestAnimationFrame is to provide optimal behavior for continuous animation; none of its advantages apply here. A looped requestAnimationFrame which does nothing inside the loop, as you currently have, is entirely appropriate if each step of the loop updates the graphics in some way, but since here nothing changes when the user is not scrolling, the loop does nothing but waste CPU time.

An example of when you should use requestAnimationFrame is if you had elements which deliberately lagged behind the scrolling and caught up after a moment. The catch-up animation should be done in a requestAnimationFrame loop which is started from the scroll event handler, and that loop should stop itself when the catch-up finishes.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
  • yes, i understand what you mean, `requestAnimationFrame` isn't the right thing for my problem. But back to my main problem, which is jittering effect in firefox..is there anything I can do to make it smoother? – Zendy May 16 '12 at 05:37
  • I don't see any jitter or flicker when I view it in Firefox 12.0 on Mac OS X, so I can't study that problem, sorry. However, if you are responding to scrolling, then there will be such effects if the response is *delayed*, which is exactly what happens when you respond to scrolling other than directly within a scroll handler, so I suggest you take out the `requestAnimationFrame` and then see what happens. – Kevin Reid May 16 '12 at 11:35
  • 3
    I think this answer is wrong... It's hard to say without the original site from the question, but it is often appropriate to implement request animation frame with a scroll operation. The scroll event fires somewhat randomly and you will get much smoother look and feel with requestAnimationFrame. See: http://www.youtube.com/watch?v=Vp524yo0p44&feature=results_main&playnext=1&list=PL4DDB2DFB422D4658 – prauchfuss Jul 29 '12 at 16:39
  • yes, that's the video that I've watched before. but yes, I haven't got a satisfying answer yet.. – Zendy Aug 01 '12 at 00:21
  • I think you're initial statement that 'you are not performing an animation' is slightly misleading. While true, the motion is dictated by user action, the motion still needs to be throttled (sometimes incorrectly called debouncing). To this end, `requestAnimationFrame` *is* useful, and *should* be used to throttle the high number of scroll events that are fired. – Matt Feb 04 '13 at 21:31
  • 1
    This answer is incorrect and misleading to those people who are coming across requestAnimationFrame for the first time. rAF is fired when the browser is attempting a paint operation - the frequency of this is determined by factors at the hardware/OS level, but ideally occurs at 60FPS. The scroll event is fired as often as single-threaded javascript will allow, typically a lot lower than 60FPS. Therefore, any javascript which changes the view continuously - an animation - should run in an rAF to maximise performance. – Simon Robb Oct 14 '15 at 10:44
  • @SimonRobb You might be right that my answer is bad advice (I've been thinking of making an actual test-page to compare the results under computation and/or rendering load) but rAF is just as subject to “single-threaded javascript” constraints as events is. You can't escape the single thread without using Web Workers or similar. – Kevin Reid Oct 14 '15 at 13:31
  • 1
    @KevinReid that's true, I worded that poorly. The more important thing is that rAF is synchronised to the browser's paint cycle. I'd be interested to see your test page if you get around to building one! – Simon Robb Oct 19 '15 at 00:06
2

I have had a similar experience and after much playing around with mouse move listeners and setInterval to increase the frequency of the animation steps, I have gone back to just using onscroll and find that on FF10 and FF 15 it is working great.

Maybe my requirements are not the same as yours - it is an element that tracks the scrollbar so onscroll was the cue to change the position of the box. It lagged behind and was jerky on FF, but worked fine on WebKit and IE. What I found was that onscroll did not fire as often on FF as on Chrome/IE.

When I initially tried this it would be on FF 5 or 6 though. Using a mouse move listener or a frequent interval, I was able to increase the frequency with which my handle scroll function go called - but this actually had the effect of making the positioning appear choppier. Just using onscroll seems to be working for me now on 10 ESR and 15, maybe they fixed something.

jonsca
  • 10,218
  • 26
  • 54
  • 62
  • yes, I ended up back to `onmousescroll` event. And then to reduce the choppy effect, I used `css transition` instead of `jquery` animation. It works better..but I'd like to learn more about `request animation frame` I believe it's a good technique.. – Zendy Sep 13 '12 at 00:43