0

I have a stack of 'pages' that I'm trying to move on mousewheel, such that the top one moves more than the one underneath it, etc. They're position: absolute, and currently I'm adjusting the CSS top to move them around, but it is veeery slow and janky.

EDIT: took down demo, problem solved.

Relevant code:

window.onScroll = (e, delta) ->
    e.preventDefault()

    minHeight = 5
    maxHeight = 800
    top_scale = 50
    second_scale = 5
    third_scale = 1
    stack = $('.card_stack').first().children()
    top = $(stack[stack.length - 1])
    second = $(stack[stack.length - 2])
    third = $(stack[stack.length - 3])

    for pair in [[top, top_scale], [second, second_scale], [third, third_scale]]
        pair[0].css('top', parseInt(pair[0].css('top'), 10) + delta*pair[1] + 'px')

$(window).mousewheel(window.onScroll)   # jQuery mousewheel plugin  

I tried looking at this in the Frames tab of Chrome to figure out what's so slow, and got this: https://dl.dropbox.com/u/407870/static/Screen%20Shot%202012-11-20%20at%201.44.33%20PM.png

It looks like there's not really much going on, but maybe I'm missing something. A previous, unanswered question related to the Frames problem I'm having: Web inspector profiling with "Frames": finding the cause of performance problems when nothing appears in the timeline

I know there are a bunch of other things that should be cleaned up before any kind of release (eg, I'm compiling Less and Coffeescript in-page) but the scrolling is my current concern, as it is central to my premise.

How can I best speed this up?

Community
  • 1
  • 1
Will Whitney
  • 127
  • 1
  • 8
  • 1
    Keep in mind that while you are scrolling the window, that event will be happening thousands of times, meaning $('.card_stack').first().children() is getting ran thousands of times very quickly, along with the .css changes you are making. Caching that selector outside of the event may improve performance in this case. – Kevin B Nov 20 '12 at 19:12
  • Also, try to round your "top" value before applying it (with Math.round()). It should increase performance. – adriendenat Nov 20 '12 at 19:16
  • @KevinB: Your comment led my to investigate how often it is, in fact, getting called, and the answer is not that often. Turns out the jQuery.mousewheel plugin doesn't fire very often, which is leading to my slow update problem. Normal onscroll events fire much more frequently. SO: Anyone know how to get onscroll events without an actual scrollable area? Or how to make that plugin fire more often? – Will Whitney Nov 20 '12 at 19:41
  • The way you are calling the plugin looks very odd... you attached a function to window.onScroll, then passed that same function into the mousewheel plugin. was that the intention? – Kevin B Nov 20 '12 at 19:44
  • @Grsmto: that does help a little, but it wasn't my main problem :/ – Will Whitney Nov 20 '12 at 19:45
  • Well, you see, when you scroll with the mousewheel, it doesn't fire an event for every position inbetween the start and stop of one tick of the mousewheel. That's where the jumpyness is happening, and can vary computer to computer (based on mouse and mouse software/drivers, cp settings, etc). I'm not sure if there will be a solution other than using a .animate rather than .css, however .animate will always be slightly behind. – Kevin B Nov 20 '12 at 19:46
  • @KevinB the actual `onscroll` callback is `window.onscroll`, not `window.onScroll` - should have named my function better - but I'm actually just attaching it to `window` so that I can access it outside that scope. – Will Whitney Nov 20 '12 at 19:48
  • @KevinB MacBook touchpad, for me. As for `animate`, I played with using CSS transitions too, and as you would expect it feels mushy. – Will Whitney Nov 20 '12 at 19:51
  • @KevinB if you toss some of that into an answer, I'll accept it. – Will Whitney Nov 20 '12 at 19:53
  • What did you consider the answer? I don't think any of what i said would be helpful enough to future users to count as an answer. – Kevin B Nov 20 '12 at 20:09
  • In my humble opinion, the best answer would be to have a look at a scroll/parallax jQuery plugin that works fine (and there are plenty of them) and check out how they achieve their scroll event (or directly use one of them). http://smashinghub.com/7-jquery-parallax-and-scrolling-effect-plugins.htm – adriendenat Nov 20 '12 at 20:49
  • Ok I think I identified the problem. It doesn't comes from the scroll event but more on what you do with it. If you check the frames you have a painting that takes 70ms. That's because you use heavy css3 rules like box-shadows. If you remove it you will have only 7ms of painting ! (so 10x performance). – adriendenat Nov 20 '12 at 20:58
  • @Grsmto Dude! That is some excellent detective work. I'll have to find other ways to make it look pretty now, but the performance boost is exactly what I was looking for. – Will Whitney Nov 20 '12 at 22:03
  • By the way, @Grsmto, removing the slow CSS was the correct answer. Post and will be selected. – Will Whitney Nov 21 '12 at 01:47

1 Answers1

0

Ok I think I identified the problem (my dear Watson). It doesn't comes from the scroll event but more on what you do with it. If you check the frames you have a painting that takes 70ms. That's because you use heavy css3 rules like box-shadows. If you remove it you will have only 7ms of painting ! (so 10x performance).

As a general rule try to avoid using css3 properties on animated elements (cause they are heavy to render for the browser !).

You can have a look at this Google I/O 2012 conference about this particular problem and how to solve it : https://www.youtube.com/watch?v=hAzhayTnhEI

adriendenat
  • 3,445
  • 1
  • 25
  • 25