change css on scroll event w/ requestAnimation Frame

[亡魂溺海] 提交于 2019-12-21 11:32:33

问题


I want to change the background color of in-viewport elements (using overflow: scroll)

So here was my first attempt: http://jsfiddle.net/2YeZG/

As you see, there is a brief flicker of the previous color before the new color is painted. Others have had similar problems.

Following the HTML5 rocks instructions, I tried to introduce requestAnimationFrame to fix this problem to no avail:

http://jsfiddle.net/RETbF/

What am I doing wrong here?


Here is a simpler example showing the same problem: http://jsfiddle.net/HJ9ng/


Filed bug with Chromium here: http://code.google.com/p/chromium/issues/detail?id=151880


回答1:


if it is only the background color, well why don't you just change the parent background color to red and once it scroll just change it to pink?

I change your CSS to that

#dad
{
    overflow-y: scroll;
    overflow-x: hidden;
    width: 100px;
    height: 600px;
    background-color:red;
}​

I remove some of you Jquery and change it to this

dad.bind('scroll', function() {
    dad.css('background-color', 'pink');
});

And I remove this line

iChild.css('backgroundColor', 'red');

But is the Red color it is important that won't work for sure http://jsfiddle.net/2YeZG/5/




回答2:


I like Manuel's Solution. But even though I don't get what you're exactly trying to do, I want to point out a few things. In your fiddle code, I saw that you included Paul Irish's Shim for requestAnimationFrame. But you never use it. (It's basically a reliable setTimeOut, nothing else) it's from frame based animations.)

So since you just want to change some CSS properties, I don't see why you would need it. Even if you want transitions, you should rely on CSS transitions.

Other than that your code could look something like

dad.bind('scroll', function() {
  dad.css('background-color', 'pink');
  eachElemNameHere.css('background-color','randomColor');
});

Also you should ideally not use something like that if you can help it. You should just add and remove class names and add all these properties in your CSS. Makes it work faster.

Also, again I don't quite get it, but you could use the jQuery function to find out each elements' position from the top to have better control.




回答3:


Your problem seems to be that you only change the background color of the elements which have already been scrolled into view. Your code expects that the browser waits for your code to handle the scroll event before the browser redraws its view. This is most probably not a guarantee given by the HTML spec. That's why it flickers.

What you should do instead is to change the elements which are going to be scrolled into view. This is related to off screen rendering or double buffering as it is called in computer games programming. You build your scene off screen and copy the finished scene to the visible frame buffer.

I modified your first JSFiddle to include a multiplier for the height of the scroll area: http://jsfiddle.net/2YeZG/13/.

dad.bind('scroll', function() {
    // new: query multiplier from input field (for demonstration only) and print message
    var multiplier = +($("#multiplier")[0].value);
    $("#message")[0].innerHTML=(multiplier*100)-100 + "% of screen rendering";

    // your original code
    var newScrollY = newScrollY = dad.scrollTop();
    var isForward = newScrollY > oldScrollY;
    var minVal = bSearch(bots, newScrollY, true);

    // new: expand covered height by the given multiplier
    //      multiplier = 1 is similar to your code
    //      multiplier = 2 would be complete off screen rendering
    var newScrollYHt = newScrollY + multiplier * dadHeight;

    // your original code (continued)
    var maxVal;
    for (maxVal = minVal; maxVal < botsLen; maxVal++) {
        var nxtTopSide = tops[maxVal];
        if (nxtTopSide >= newScrollYHt) {
            break;
        }
    }
    maxVal = Math.min(maxVal, botsLen);
    $(dadKids.slice(minVal, maxVal)).css('background', 'pink');
});

Your code had a multiplier of 1, meaning that you update the elements which are currently visible (100% of scroll area height). If you set the multiplier to 2, you get complete off screen updates for all your elements. The browser updates enough elements to the new background color so that even a 100% scroll would show updated elements. Since the browser seldom scrolls 100% of the area in one step (depends of the operating system and the scroll method!), it may be sufficient to reduce the multiplier to e.g. 1.5 (meaning 50% off screen rendering). On my machine (Google Chrome, Mac OS X with touch pad) I cannot produce any flicker if the multiplier is 1.7 or above.

BTW: If you do something more complicated than just changing the background color, you should not do it again and again. Instead you should check whether the element has already been updated and perform the change only afterwards.



来源:https://stackoverflow.com/questions/12515323/change-css-on-scroll-event-w-requestanimation-frame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!