瀏覽器原生支援平滑滾動

張鑫旭發表於2018-10-22

瀏覽器從去年年底開始,已經開始支援瀏覽器的原生平滑滾動定位,CSS scroll-behavior屬性和JS scrollIntoView()方法都可以。

一、CSS scroll-behavior與平滑滾動

scroll-behavior:smooth寫在滾動容器元素上,可以讓容器(非滑鼠手勢觸發)的滾動變得平滑。

我們先看一個實際的案例。

8年前“無JavaScript純CSS實現選項卡輪轉切換效果”這篇文章介紹了一種利用錨點定位純CSS實現選項卡切換的技術(本質上是觸發滾動條滾動)。

可以狠狠地點選這裡:無JavaScript實現的切換效果demo

實現後的效果參見下GIF截圖:

錨點選項卡切換

基本功能可以滿足,但有兩個問題,一是由於改變location的hash實現的定位,會觸發瀏覽器原生滾動行為,體驗不好;二是選項卡內容的切換“邦邦邦”過於生硬。

於是,後來,我發明了一種基於控制元件元素focus觸發滾動重定位的特性實現的純CSS選項卡切換效果,在《CSS世界》這本書overflow章節有提到,您可以狠狠的點選這裡:focus錨點定位和overflow的選項卡切換demo

focus輸入框與選項卡切換

也是純CSS實現,沒有任何JavaScript程式碼,相比直接利用<a>元素的href錨點跳轉方法,此方法不會觸發瀏覽器外部窗體的滾動,體驗更上一層樓,但是還有一個問題,那就是選項卡內容切換的時候,還是“邦邦邦”這種乾巴巴的效果,並沒有滑來滑去那種溼溼的效果。

不要擔心,現在有了CSS scroll-behavior,則平滑滾動的問題也可以解決了。您可以狠狠地點選這裡:CSS scroll-behavior選項卡平滑滾動demo

相比之前乾巴巴的實現,就多了這麼一句CSS——scroll-behavior:smooth

.box {
    scroll-behavior: smooth; 
    overflow: hidden; 
}複製程式碼

結果一股如沐春風的互動效果撲面而來,參見下面視訊截圖效果(掘金文章不支援嵌入視訊,可去原文檢視),或者腦補下面的靜態圖:

瀏覽器原生支援平滑滾動

更簡單更實際的用途

其實scroll-behavior的使用沒有那麼多花頭,你就記住這麼一句話——

凡是需要滾動的地方都加一句scroll-behavior:smooth就好了!

你別管他用不用得到,也不用管瀏覽器相容性如何,你都加上。這就像一個不要錢的免費抽獎,沒有中獎,沒關係,又沒什麼損失,中獎了自然好,錦上添花!scroll-behavior:smooth就是這種尿性。

舉個例子,在PC瀏覽器中,網頁預設滾動是在<html>標籤上的,移動端大多數在<body>標籤上,於是,我加上這麼一句:

html, body { scroll-behavior:smooth; }複製程式碼

此時,點選如下程式碼所示的“返回頂部”連結,就會平滑滾動到頂部。

<a href="#">返回頂部</a>複製程式碼

從這一點來看,業界瀏覽器的CSS reset都可以加上這麼一條規則:

html, body { scroll-behavior:smooth; }複製程式碼

二、JS scrollIntoView與平滑滾動

DOM元素的scrollIntoView()方法是一個IE6瀏覽器也支援的原生JS API,可以讓元素進入視區,通過觸發滾動容器的定位實現。

隨著Chrome和Firefox瀏覽器開始支援CSS scroll-behavior屬性,順便對,scrollIntoView()方法進行了升級,使支援更多引數,其中一個引數就是可以使滾動平滑。

語法如下:

target.scrollIntoView({
    behavior: "smooth"
});複製程式碼

我們隨便開啟一個有連結的頁面,把首個連結滾動到螢幕外,然後控制檯輸入類似下面程式碼,我們就可以看到頁面平滑滾動定位了:

document.links[0].scrollIntoView({
    behavior: "smooth"
});複製程式碼

如下視訊截圖:

其它:

  • scrollIntoView()升級後的方法,除了支援'behavior',還有'block''inline'等引數,有興趣可以參閱MDN相關文件
  • 如果我們的網頁已經通過CSS設定了scroll-behavior:smooth宣告,則我們直接執行target.scrollIntoView()方法就會有平滑滾動,無需再額外設定behavior引數。例如,如果你是在鑫空間原站瀏覽的此文章,開啟控制檯,執行下面程式碼,就可以看到平滑滾動效果了:
    document.forms[0].scrollIntoView();複製程式碼

三、JS平滑滾動向下相容處理

JS實現平滑滾動並不難,jQuery中animate()方法:

scrollContainer.animate({
    scrollTop: 0
});複製程式碼

或者使用requestAnimationFrame API這類原生JS也能實現。例如下面這個我速寫的個方法:

/**
 @description 頁面垂直平滑滾動到指定滾動高度
 @author zhangxinxu(.com)
*/
var scrollSmoothTo = function (position) {
    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function(callback, element) {
            return setTimeout(callback, 17);
        };
    }
    // 當前滾動高度
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    // 滾動step方法
    var step = function () {
        // 距離目標滾動距離
        var distance = position - scrollTop;
        // 目標滾動位置
        scrollTop = scrollTop + distance / 5;
        if (Math.abs(distance) < 1) {
            window.scrollTo(0, position);
        } else {
            window.scrollTo(0, scrollTop);
            requestAnimationFrame(step);
        }
    };
    step();
};複製程式碼

使用的是自己私藏緩動動畫JS小演算法,滾動先快後慢。

使用如下,例如,我們希望網頁平滑滾動到頂部,直接:

scrollSmoothTo(0);複製程式碼

就可以了。

難的是如何支援平滑滾動的瀏覽器原生處理,不支援的瀏覽器還是使用老的JS方法處理。例如IE瀏覽器和Safari目前尚未支援原生平滑滾動。

scroll-behavior瀏覽器相容性

需要分別處理,我的JS判斷處理如下:

if (typeof window.getComputedStyle(document.body).scrollBehavior == 'undefined') {
   // 傳統的JS平滑滾動處理程式碼...
}複製程式碼

這樣就可以無縫對接了。

(本文完)


相關文章