在所有浏览器中为我的网站启用平滑滚动

Posted

技术标签:

【中文标题】在所有浏览器中为我的网站启用平滑滚动【英文标题】:Enable smooth scrolling for my website in all browsers 【发布时间】:2013-10-21 08:52:37 【问题描述】:

我正在使用Stellar 和Skrollr 库开发一个视差滚动网站。由于 Firefox 的平滑滚动功能,该网站在 Firefox 中表现完美,但在 Chrome 中,使用鼠标滚轮滚动很生涩,视差效果几乎被破坏。有什么方法可以在所有浏览器中使用鼠标滚轮平滑滚动,同时保持性能?

【问题讨论】:

你能发布你的代码演示吗?插件自己的网站似乎可以流畅地滚动动画,问题可能与您对其代码的实现有关。没有看到这一点,我们无能为力。 请不要这样做,任何时候我在我关闭的网站上看到这个。在我看过的任何网站上的游戏 PC 上的 Chrome 浏览器中的延迟。 【参考方案1】:

我找到了两个 jQuery 插件,可以满足你的需求。

Simplr-SmoothScroll // 来源:SE Question

jQuery SmoothWheel


编辑:因为 cmets 而淘汰了 SmoothWheel - 它已经很久没有更新过了,而且 SmoothScroll 似乎维护得很好。

【讨论】:

Simplr-SmoothScroll 非常好,但是当您使用 track-padmac 或任何 laptop 时,它的行为会突然出现,并且只需轻轻一按即可滚动整个窗口。 Simplr-SmoothScroll有很大的问题,使用track-pad的时候,请在使用前检查该问题。【参考方案2】:

如果您是Cargo cult programmer,请使用 jQuery。仅当您是 Real programmer 时才继续。

拧jQuery.animate(),了解背后的数学并选择一种算法。 Robert Penner has a nice demo,我选择了 EaseOutQuad。

阅读如何处理鼠标滚轮跨浏览器样式here,然后做一些more reading。

在此代码中,我选择不支持 IE 8 及更早版本。这个想法是连接***事件,防止它(因为默认行为是生涩的跳跃)并执行自己的平滑跳跃

Math.easeOutQuad = function (t, b, c, d)  t /= d; return -c * t*(t-2) + b; ;

(function()  // do not mess global space
var
  interval, // scroll is being eased
  mult = 0, // how fast do we scroll
  dir = 0, // 1 = scroll down, -1 = scroll up
  steps = 50, // how many steps in animation
  length = 30; // how long to animate
function MouseWheelHandler(e) 
  e.preventDefault(); // prevent default browser scroll
  clearInterval(interval); // cancel previous animation
  ++mult; // we are going to scroll faster
  var delta = -Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); // cross-browser
  if(dir!=delta)  // scroll direction changed
    mult = 1; // start slowly
    dir = delta;
  
  // in this cycle, we determine which element to scroll
  for(var tgt=e.target; tgt!=document.documentElement; tgt=tgt.parentNode) 
    var oldScroll = tgt.scrollTop;
    tgt.scrollTop+= delta;
    if(oldScroll!=tgt.scrollTop) break;
    // else the element can't be scrolled, try its parent in next iteration
  
  var start = tgt.scrollTop;
  var end = start + length*mult*delta; // where to end the scroll
  var change = end - start; // base change in one step
  var step = 0; // current step
  interval = setInterval(function() 
    var pos = Math.easeOutQuad(step++,start,change,steps); // calculate next step
    tgt.scrollTop = pos; // scroll the target to next step
    if(step>=steps)  // scroll finished without speed up - stop animation
      mult = 0; // next scroll will start slowly
      clearInterval(interval);
    
  ,10);


// nonstandard: Chrome, IE, Opera, Safari
window.addEventListener("mousewheel", MouseWheelHandler, false); 
// nonstandard: Firefox
window.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
)();

正如你所看到的in this demo,我更喜欢尽可能少的缓动,以避免生涩的滚动。阅读上面的 cmets 并设计适合您项目的自己的滚动。

注意:鼠标滚轮也可以连接到触摸板,但不能连接到上/下键。您也应该考虑挂钩关键事件。

【讨论】:

这是很棒的代码带解释!当用户使用实际滚动条滚动时,我将如何添加平滑滚动? (即不是用鼠标滚轮,而是实际点击并拖动滚动条) 另外,假设用户一直滚动到顶部(或底部)。你怎么能自动向下滚动一点,然后反弹回来?有点像弹性滚动 @Jessica 那么我建议选择退出三次算法from here,只要确保在页面底部留出足够的空白空间即可。将来我相信每个浏览器都会支持很好的滚动感觉,所以这个脚本会过时。请参阅Chrome announcement。滚动条滚动运气不好:-/这是一个浏览器功能,没有“onscrollbarscroll”事件。 @JanTuroň 谢谢!希望浏览器能够实现这一点!无论如何,我试过了,jsfiddle.net/jgeqda91 每次滚动都会反弹,并且不会在顶部和底部反弹。我只希望它一直弹到顶部或底部时反弹。我该如何实施? (或者我应该问一个新问题吗?) @Jessica 我猜你需要添加一个条件,如果结束位置在(或非常接近)顶部或底部,不包括用于反弹的填充,使用后立方,否则只使用立方.你会试试吗?【参考方案3】:

我没有太多时间,但我尝试编写一个(跨浏览器和脏)平滑滚动功能。当您停止滚动时,它会平稳减速。您可以稍微重写一下,使其符合您的需求。

在这里试一试:

平滑滚动:

function getScrollTop()
    if(typeof pageYOffset!= 'undefined')
        //most browsers except IE before #9
        return pageYOffset;
     else 
        var B = document.body; //IE 'quirks'
        var D = document.documentElement; //IE with doctype
        D = (D.clientHeight) ? D : B;
        return D.scrollTop;
    


var timeouts = [];
var scrolling = false;
var scroller;
var scrollTop = getScrollTop();
var timeMs;
var alter = false;
var speed = 5;
window.onscroll = function() 
    if(alter) 
        var timeDif = new Date().getMilliseconds() - timeMs;
        speed = 5 - (timeDif / 50);
        console.log(speed);
    
    timeMs = new Date().getMilliseconds();
    alter = !alter;
    var scrollDirection = getScrollTop() - scrollTop;
    scrollDirection = scrollDirection / Math.abs(scrollDirection);
    scrollTop = getScrollTop();
    clearTimeout(scroller);
    scroller = setTimeout(function()
        console.log('smooth scrolling active');
        if(!scrolling) 
            timeouts.length = 0;
            scrolling = true;
            var steps = 50;
            var delay = 6;
            for(var i = 0; i < steps; i++) 
                (function(i)
                    var timeout = setTimeout(function()
                        var perc = i / steps; 
                        var val = (perc == 1) ? 1 : (-Math.pow(2, -10 * perc) + 1); 
                        var scrollY = val * speed * scrollDirection;
                        window.scrollTo(0, getScrollTop() + scrollY);
                        setTimeout(function()
                            if(i == (steps - 1)) scrolling = false;
                        , steps * delay);
                    , (i * delay));
                    timeouts.push(timeout);
                )(i);
            
        
    , 50);
;

http://jsfiddle.net/ubawR/4/

【讨论】:

【参考方案4】:

只有 chrome 可以试试这个 - https://github.com/im4aLL/chromeSmoothScroll 只有 1 KB

【讨论】:

我发现这个脚本最适合我的视差网站。好处包括:特定于浏览器(我只针对 Chrome),内置键盘功能,并且不需要额外的库(Simplr-SmoothScroll 需要 JQuery 鼠标滚轮)。我确实发现将速度从默认的 800 调整到 200 会产生最接近 FireFox 的效果。还注意到鼠标滚轮滚动的速度被考虑在内。大旋转给了大卷轴。无论鼠标滚轮动作是什么(大滚动或短滚动),其他脚本都会指定滚动距离。【参考方案5】:

Simplr-SmoothScroll 有一个错误 - 当身体高度不是自动时,它不适用于身体。

我找到了另一个插件,它对我来说是完美的解决方案。 https://github.com/inuyaksa/jquery.nicescroll

下载库 (demo) 并添加到开头

// 1. Simple mode, it styles document scrollbar:
$(document).ready(function()   
    $("body").niceScroll();
);

【讨论】:

谢谢!由于触控板问题,我们也使用此插件,在我们这边也可以正常工作。【参考方案6】:

基本上,由于重绘和重排,滚动会导致抖动。如果您可以检查并减少这些回流,您可能会获得滚动性能。

并检查 onScroll 事件回调函数是否执行任何昂贵的逻辑。并且是否有任何内存泄漏。

Chrome 开发者工具栏堆快照对于检测内存泄漏以及查看重绘和重排非常有用。

【讨论】:

我知道这会导致滚动不顺畅,但我正在寻找一种通常使用鼠标滚轮平滑滚动的方法。例如,在一个简单的文本页面上,滚动一圈默认向下约 3 行,一次跳转。我希望它走同样的距离但平稳。 是的,我现在明白了,我在 js fiddle 中添加了一个示例代码。这适用于铬。如果您对 Firefox 没有任何问题,请删除相关的 if 条件。 [link] (jsfiddle.net/Y6xZM/1) 你可以使用 MOUSE_WHEEL_GAIN 来增加滚动量。

以上是关于在所有浏览器中为我的网站启用平滑滚动的主要内容,如果未能解决你的问题,请参考以下文章

React useRef 将平滑滚动添加到除 Internet Explorer 之外的所有浏览器都支持的 div

如何在 android 中以编程方式在小米手机安全应用程序中为我的应用程序启用自动启动选项

如何在wpf treeview控件上启用平滑滚动

是否可以预加载所有 tableview 单元格以启用平滑滚动?

仅当窗口缩小时如何启用滚动条?

如何在 iOS Safari 上启用 iframe 滚动条