滑向未來(lái)(現(xiàn)代 JavaScript 與 CSS 滾動(dòng)實(shí)現(xiàn)指南)

image

滑向未來(lái)(現(xiàn)代 JavaScript 與 CSS 滾動(dòng)實(shí)現(xiàn)指南)

原文鏈接: evilmartians.com
譯文鏈接: 眾成

一些(網(wǎng)站)滾動(dòng)的效果是如此令人著迷但你卻不知該如何實(shí)現(xiàn),本文將為你揭開它們的神秘面紗垒玲。我們將基于最新的技術(shù)與規(guī)范為你介紹最新的 JavaScript 與 CSS 特性盛泡,(當(dāng)你付諸實(shí)踐時(shí)榆芦,)將使你的頁(yè)面滾動(dòng)更平滑拴还、美觀且性能更好。

大多數(shù)的網(wǎng)頁(yè)的內(nèi)容都無(wú)法在一屏內(nèi)全部展現(xiàn),因而(頁(yè)面)滾動(dòng)對(duì)于用戶而言是必不可少的。對(duì)于前端工程師與 UX 設(shè)計(jì)師而言盯滚,跨瀏覽器提供良好的滾動(dòng)體驗(yàn),同時(shí)符合設(shè)計(jì)(要求)酗电,無(wú)疑是一個(gè)挑戰(zhàn)魄藕。盡管 web 標(biāo)準(zhǔn)的發(fā)展速度遠(yuǎn)超從前,但代碼的實(shí)現(xiàn)往往是落后的撵术。下文將為你介紹一些常見的關(guān)于滾動(dòng)的案例背率,檢查一下你所用的解決方案是否被更優(yōu)雅的方案所代替。

消逝的滾動(dòng)條

在過(guò)去的三十年里嫩与,滾動(dòng)條的外觀不斷改變以符合設(shè)計(jì)的趨勢(shì)寝姿,設(shè)計(jì)師們?yōu)椋L動(dòng)條的)顏色、陰影划滋、上下箭頭的形狀與邊框的圓角實(shí)驗(yàn)了多種風(fēng)格饵筑。以下是 Windows 上的變化歷程:

Design of Windows scrollbars over time

(Windows 上的滾動(dòng)條)

在2011年,蘋果設(shè)計(jì)師從 ios 上獲得靈感处坪,為如何定義“美觀的”滾動(dòng)條確定了方向根资。所有滾動(dòng)條均從 Mac 電腦中消失,不再占據(jù)任何頁(yè)面空間同窘,只有在用戶觸發(fā)滾動(dòng)時(shí)(滾動(dòng)條)才會(huì)重新出現(xiàn)(有些用戶會(huì)設(shè)置不隱藏滾動(dòng)條)玄帕。

Design of Mac scrollbars over time

(Mac 上的滾動(dòng)條)

滾動(dòng)條安靜地消逝并未引起蘋果粉絲的不滿,已經(jīng)習(xí)慣了 iPhone 與 iPad 上滾動(dòng)方式的用戶很快地習(xí)慣了這一設(shè)計(jì)塞椎。大多數(shù)開發(fā)人員與設(shè)計(jì)師都認(rèn)為這是一個(gè)“好消息”桨仿,因?yàn)橛?jì)算滾動(dòng)條的寬度可真是件苦差事。

然而案狠,我們生活在一個(gè)擁有眾多操作系統(tǒng)與瀏覽器的世界中服傍,它們(對(duì)于滾動(dòng))的實(shí)現(xiàn)各不相同。如果你和我們一樣是一名 Web 開發(fā)者骂铁,你可不能把“滾動(dòng)條問(wèn)題”置之不理吹零。

以下將為你介紹一些小技巧,使你的用戶在滾動(dòng)時(shí)有更好的體驗(yàn)拉庵。

隱藏但可滾動(dòng)

先來(lái)看看一個(gè)關(guān)于模態(tài)框的經(jīng)典例子灿椅。當(dāng)它被打開的時(shí)候,主頁(yè)面應(yīng)該停止?jié)L動(dòng)。在 CSS 中有如下的快捷實(shí)現(xiàn)方式:

body {
  overflow: hidden;
}

但上述代碼會(huì)帶來(lái)一點(diǎn)不良的副作用:

Jitter when a scrollbar disappears

(注意紅色剪頭)

在這個(gè)示例中茫蛹,為了演示目的操刀,我們?cè)?Mac 系統(tǒng)中設(shè)置了強(qiáng)制顯示滾動(dòng)條,因而用戶體驗(yàn)與 Windows 用戶相似婴洼。

我們?cè)撊绾谓鉀Q這個(gè)問(wèn)題呢骨坑?如果我們知道滾動(dòng)條的寬度,每次當(dāng)模態(tài)框出現(xiàn)時(shí)柬采,可在主頁(yè)面的右邊設(shè)置一點(diǎn)邊距欢唾。

由于不同的操作系統(tǒng)與瀏覽器對(duì)滾動(dòng)條的寬度不一,因而獲取它的寬度并不容易粉捻。在Mac 系統(tǒng)中礁遣,無(wú)論任何瀏覽器(滾動(dòng)條)都是統(tǒng)一15px,然而 Windows 系統(tǒng)可會(huì)令開發(fā)者發(fā)狂:

Scrollbar sizes under different browsers

(“百花齊放”的寬度)

注意肩刃,以上僅是 Windows 系統(tǒng)下基于當(dāng)前最新版瀏覽器(測(cè)試所得)的結(jié)果祟霍。以前的(瀏覽器)版本(寬度)可能有所不同,也沒(méi)人知道未來(lái)(滾動(dòng)條的寬度)會(huì)如何變化树酪。

不同于猜測(cè)(滾動(dòng)條的寬度)浅碾,你可以通過(guò) JavaScript 計(jì)算它的寬度(譯者注:實(shí)測(cè)以下代碼僅能測(cè)出原始的寬度,通過(guò) CSS 改變了滾動(dòng)條寬度后续语,以下代碼也無(wú)法測(cè)出實(shí)際寬度):

const outer = document.createElement('div');
const inner = document.createElement('div');
outer.style.overflow = 'scroll';
document.body.appendChild(outer);
outer.appendChild(inner);
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
document.body.removeChild(outer);

盡管僅僅七行代碼(就能測(cè)出滾動(dòng)條的寬度),但有數(shù)行代碼是操作 DOM 的厦画。(為性能起見疮茄,)如非必要,盡量避免進(jìn)行 DOM 操作根暑。

解決這個(gè)問(wèn)題的另一個(gè)方法是在模態(tài)框出現(xiàn)時(shí)仍保留滾動(dòng)條力试,以下是基于這思路的純 CSS 實(shí)現(xiàn):

html {
  overflow-y: scroll;
}

盡管“模態(tài)框抖動(dòng)”問(wèn)題解決了,但整體的外觀卻被一個(gè)無(wú)法使用的滾動(dòng)條影響了排嫌,這無(wú)疑是設(shè)計(jì)中的硬傷畸裳。

在我們看來(lái),更好的解決方案是完全地隱藏滾動(dòng)條淳地。純粹用 CSS 也是可以實(shí)現(xiàn)的怖糊。該方法(達(dá)到的效果)和 macOS 的表現(xiàn)并不是完全一致,(當(dāng)用戶)滾動(dòng)時(shí)滾動(dòng)條仍然是不可見的颇象。滾動(dòng)條總是處于不可見狀態(tài)伍伤,然而頁(yè)面是可被滾動(dòng)的。對(duì)于Chrome遣钳,Safari 和 Opera 而言扰魂,可以使用以下的 CSS:

.container::-webkit-scrollbar {
  display: none;
}

IE 或 Edge 可用以下代碼:

.container {
  -ms-overflow-style: none;
}

至于 Firefox,很不幸,沒(méi)有任何辦法隱藏滾動(dòng)條劝评。

正如你所見姐直,并沒(méi)有任何銀彈。任何解決方案都有它的優(yōu)點(diǎn)與缺點(diǎn)蒋畜,應(yīng)根據(jù)你項(xiàng)目的需要選擇最合適的声畏。

外觀爭(zhēng)議

需要承認(rèn)的是,滾動(dòng)條的樣子在部分操作系統(tǒng)上并不好看百侧。一些設(shè)計(jì)師喜歡完全掌控他們(所設(shè)計(jì))應(yīng)用的樣式砰识,任何一絲細(xì)節(jié)也不放過(guò)。在 GitHub 上有上百個(gè)庫(kù)借助 JavaScript 取代系統(tǒng)滾動(dòng)條的默認(rèn)實(shí)現(xiàn)佣渴,以達(dá)到自定義的效果辫狼。

但如果你想根據(jù)現(xiàn)有的瀏覽器定制一個(gè)滾動(dòng)條呢?(很遺憾辛润,)并沒(méi)有通用的 API膨处,每個(gè)瀏覽器都有其獨(dú)特的代碼實(shí)現(xiàn)冕屯。

盡管5.5版本以后的 IE 瀏覽器允許你修改滾動(dòng)條的樣式留夜,但它只允許你修改滾動(dòng)條的顏色。以下是如何重新繪制(滾動(dòng)條)拖動(dòng)部分與箭頭的代碼:

body {
  scrollbar-face-color: blue;
}

但只改變顏色對(duì)提高用戶體驗(yàn)而言幫助不大干厚。據(jù)此乎澄,WebKit 的開發(fā)者在2009年提出了(修改滾動(dòng)條)樣式的方案突硝。以下是使用 -webkit 前綴在支持相關(guān)樣式的瀏覽器中模擬 macOS 滾動(dòng)條樣式的代碼:

::-webkit-scrollbar {
  width: 8px;
}
::-webkit-scrollbar-thumb {
  background-color: #c1c1c1;
  border-radius: 4px;
}

Chrome、Safari置济、Opera 甚至于 UC 瀏覽器或者三星自帶的桌面瀏覽器都支持(上述 CSS)解恰。Edge 也有計(jì)劃實(shí)現(xiàn)它們。但三年過(guò)去了浙于,該計(jì)劃仍在中等優(yōu)先級(jí)中(而尚未被實(shí)現(xiàn))护盈。

當(dāng)我們討論滾動(dòng)條的定制時(shí),Mozilla 基金會(huì)基本上是無(wú)視了設(shè)計(jì)師的需求羞酗。(有開發(fā)者在)17年前就已經(jīng)提出了一個(gè)希望修改滾動(dòng)條樣式的請(qǐng)求腐宋。而就在幾個(gè)月前,Jeff Griffiths(Firefox 瀏覽器總監(jiān))終于為這個(gè)問(wèn)題作出了回答:

“除非團(tuán)隊(duì)中有人對(duì)此有興趣檀轨,否則我對(duì)此毫不關(guān)心胸竞。”

公平地說(shuō)裤园,從 W3C 的角度看來(lái)撤师,盡管 WebKit 的實(shí)現(xiàn)得到廣泛的支持,但它仍然不是標(biāo)準(zhǔn)∨±浚現(xiàn)有的為滾動(dòng)條修改樣式的草案剃盾,是基于 IE 的:僅能修改它的顏色腺占。

伴隨著請(qǐng)求如同 WebKit 一樣支持滾動(dòng)條樣式修改 issue 的提交,爭(zhēng)議仍在繼續(xù)痒谴。如果你想影響 CSS 工作小組衰伯,是時(shí)候參與討論了。也許這不是優(yōu)先級(jí)最高的問(wèn)題积蔚,但(如同 WebKit 一樣修改滾動(dòng)條樣式)得到標(biāo)準(zhǔn)化后意鲸,能使很多前端工程師與設(shè)計(jì)師輕松很多。

流暢的操作體驗(yàn)

對(duì)于滾動(dòng)而言尽爆,最常見的任務(wù)是登錄頁(yè)的導(dǎo)航(跳轉(zhuǎn))怎顾。通常,它是通過(guò)錨點(diǎn)鏈接來(lái)完成的漱贱。只需要知道元素的 id 即可:

<a href="#section">Section</a>

點(diǎn)擊該鏈接會(huì) 到(該錨點(diǎn)對(duì)應(yīng)的)區(qū)塊上槐雾,(然而) UX 設(shè)計(jì)師一般會(huì)堅(jiān)持認(rèn)為該過(guò)程應(yīng)是平滑地運(yùn)動(dòng)的。GitHub 上有大量造好的輪子(幫你解決這個(gè)問(wèn)題)幅狮,然而它們或多或少都用到 JavaScript募强。(其實(shí))只用一行代碼也能實(shí)現(xiàn)同樣的效果,最近DOM API 中的 Element.scrollIntoView() 可以通過(guò)傳入配置對(duì)象來(lái)實(shí)現(xiàn)平滑滾動(dòng):

elem.scrollIntoView({
  behavior: 'smooth'
});

然而該屬性兼容性較差且仍是通過(guò)腳本(來(lái)控制樣式)崇摄。如有可能擎值,應(yīng)盡量少用額外的腳本。

幸運(yùn)的是逐抑,有一個(gè)全新的 CSS 屬性(仍在工作草案中)鸠儿,可以用簡(jiǎn)單的一行代碼改變整個(gè)頁(yè)面滾動(dòng)的行為。

html {
  scroll-behavior: smooth;
}

結(jié)果如下:

Jumping from one section to another

(從一個(gè)區(qū)塊跳到另一個(gè))

Scrolling smoothly

(平滑地滾動(dòng))

你可以在 codepen 上試驗(yàn)這個(gè)屬性厕氨。在撰寫本文時(shí)捆交,scroll-behavior 僅在 Chrome、 Firefox 與 Opera 上被支持腐巢,但我們希望它能被廣泛支持,因?yàn)槭褂?CSS (比使用 JavaScript)在解決頁(yè)面滾動(dòng)問(wèn)題時(shí)優(yōu)雅得多玄括,并更符合“漸進(jìn)增強(qiáng)”的模式冯丙。

粘性 CSS

另一個(gè)常見的需求是根據(jù)滾動(dòng)方向動(dòng)態(tài)地定住元素,即有名的“粘性(即 CSS 中的position: sticky)”效應(yīng)遭京。

A sticky element

(一個(gè)粘性元素)

在以前的日子里胃惜,要實(shí)現(xiàn)一個(gè)“粘性”元素需要編寫復(fù)雜的滾動(dòng)處理函數(shù)去計(jì)算元素的大小。(然而)該函數(shù)較難處理元素在“黏住”與“不黏住”之間微小的延遲哪雕,(通常會(huì))導(dǎo)致(元素)抖動(dòng)的出現(xiàn)船殉。通過(guò) JavaScript 來(lái)實(shí)行(“粘性”元素)也有性能上的問(wèn)題,特別是在(需要)調(diào)用 [Element.getBoundingClientRect() ]時(shí)(https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect)斯嚎。%E3%80%82)

不久之前利虫,CSS 實(shí)現(xiàn)了 position: sticky 屬性挨厚。只需通過(guò)指定(某方向上的)偏移量即可實(shí)現(xiàn)我們想要的效果。

.element {
  position: sticky;
  top: 50px;
}

(編寫上述代碼后糠惫,)剩下的就交由瀏覽器實(shí)現(xiàn)即可疫剃。你可以在 codepen 上試驗(yàn)一下。撰寫本文之時(shí)硼讽,position: sticky 在各式瀏覽器(包括移動(dòng)端瀏覽器)上支持良好巢价,所以如果你還在使用 JavaScript 去解決這個(gè)問(wèn)題的話,是時(shí)候換成純 CSS 的實(shí)現(xiàn)了固阁。

全面使用函數(shù)節(jié)流

從瀏覽器的角度看來(lái)壤躲,滾動(dòng)是一個(gè)事件,因此在 JavaScript 中是使用一個(gè)標(biāo)準(zhǔn)化的事件監(jiān)聽器 addEventListener 去處理它: 备燃,

window.addEventListener('scroll', () => {
  const scrollTop = window.scrollY;
  /* doSomething with scrollTop */
});

用戶往往高頻率地滾動(dòng)(頁(yè)面)碉克,但如果滾動(dòng)事件觸發(fā)太頻繁的話,會(huì)導(dǎo)致性能上的問(wèn)題赚爵,可以通過(guò)使用函數(shù)節(jié)流這一技巧去優(yōu)化它棉胀。

window.addEventListener('scroll', throttle(() => {
  const scrollTop = window.scrollY;
  /* doSomething with scrollTop */
}));

你需要定義一個(gè)節(jié)流函數(shù)包裝原來(lái)的事件監(jiān)聽函數(shù),(節(jié)流函數(shù)是)減少被包裝函數(shù)的執(zhí)行次數(shù)冀膝,只允許它在固定的時(shí)間間隔之內(nèi)執(zhí)行一次:

function throttle(action, wait = 1000) {
  let time = Date.now();
  return function() {
    if ((time + wait - Date.now()) < 0) {
        action();
        time = Date.now();
    }
  }
}

為了使(節(jié)流后的)滾動(dòng)更平滑唁奢,你可以通過(guò)使用 window.requestAnimationFrame()來(lái)實(shí)現(xiàn)函數(shù)節(jié)流:

function throttle(action) {
  let isRunning = false;
  return function() {
    if (isRunning) return;
    isRunning = true;
    window.requestAnimationFrame(() => {
      action();
      isRunning = false;
    });
  }
}

當(dāng)然,你可以通過(guò)現(xiàn)有的開源輪子來(lái)實(shí)現(xiàn)窝剖,就像 Lodash 一樣麻掸。你可以訪問(wèn) codepen 來(lái)看看上述解決方案與 Lodash 中的 _.throttle 之間的區(qū)別。

使用哪個(gè)(開源庫(kù))并不重要赐纱,重要的是在需要的時(shí)候脊奋,記得優(yōu)化你(頁(yè)面中的)滾動(dòng)處理函數(shù)。

在視窗中顯示

當(dāng)你需要實(shí)現(xiàn)圖片懶加載或者無(wú)限滾動(dòng)時(shí)疙描,需要確定元素是否出現(xiàn)在視窗中诚隙。這可以在事件監(jiān)聽器中處理,最常見的解決方案是使用 lement.getBoundingClientRect()

window.addEventListener('scroll', () => {
  const rect = elem.getBoundingClientRect();
  const inViewport = rect.bottom > 0 && rect.right > 0 &&
                     rect.left < window.innerWidth &&
                     rect.top < window.innerHeight;
});

上述代碼的問(wèn)題在于每次調(diào)用 getBoundingClientRect 時(shí)都會(huì)觸發(fā)回流起胰,嚴(yán)重地影響了性能久又。在事件處理函數(shù)中調(diào)用( getBoundingClientRect )尤為糟糕,就算使用了函數(shù)節(jié)流(的技巧)也可能對(duì)性能沒(méi)多大幫助效五。 (回流是指瀏覽器為局部或整體地重繪某個(gè)元素地消,需要重新計(jì)算該元素在文檔中的位置與形狀。)

在2016年后畏妖,可以通過(guò)使用 Intersection Observer 這一 API 來(lái)解決問(wèn)題脉执。它允許你追蹤目標(biāo)元素與其祖先元素或視窗的交叉狀態(tài)。此外戒劫,盡管只有一部分元素出現(xiàn)在視窗中半夷,哪怕只有一像素婆廊,也可以選擇觸發(fā)回調(diào)函數(shù):

const observer = new IntersectionObserver(callback, options);

observer.observe(element);

(點(diǎn)擊這里,查看觸發(fā)回流的 DOM 屬性和方法玻熙。)

此 API 被廣泛地支持否彩,但仍有一些瀏覽器需要 polyfill。盡管如此嗦随,它仍是目前最好的解決方案列荔。

滾動(dòng)邊界問(wèn)題

如果你的彈框或下拉列表是可滾動(dòng)的,那你務(wù)必要了解連鎖滾動(dòng)相關(guān)的問(wèn)題:當(dāng)用戶滾動(dòng)到(彈框或下拉列表)末尾(后再繼續(xù)滾動(dòng)時(shí))枚尼,整個(gè)頁(yè)面都會(huì)開始滾動(dòng)贴浙。

Scrolling chaining

(連鎖滾動(dòng)的表現(xiàn))

當(dāng)滾動(dòng)元素到達(dá)底部時(shí),你可以通過(guò)(改變)頁(yè)面的 overflow 屬性或在滾動(dòng)元素的滾動(dòng)事件處理函數(shù)中取消默認(rèn)行為來(lái)解決這問(wèn)題署恍。

如果你選擇使用 JavaScript (來(lái)處理)崎溃,請(qǐng)記住要處理的不是“scroll(事件)”,而是每當(dāng)用戶使用鼠標(biāo)滾輪或觸摸板時(shí)觸發(fā)的“wheel(事件)”

function handleOverscroll(event) {
  const delta = -event.deltaY;
  if (delta < 0 && elem.offsetHeight - delta > elem.scrollHeight - elem.scrollTop) {
    elem.scrollTop = elem.scrollHeight;
    event.preventDefault();
    return false;
  }
  if (delta > elem.scrollTop) {
    elem.scrollTop = 0;
    event.preventDefault();
    return false;
  }
  return true;
}

不幸的是盯质,這個(gè)解決方案不太可靠袁串。同時(shí)可能對(duì)(頁(yè)面)性能產(chǎn)生負(fù)面影響。

過(guò)度滾動(dòng)對(duì)移動(dòng)端的影響尤為嚴(yán)重呼巷。Loren Brichter 在 iOS 的 Tweetie 應(yīng)用上創(chuàng)造了一個(gè)“下拉刷新”的新手勢(shì)囱修,這在 UX 社區(qū)中引起了轟動(dòng):包括 Twitter 與 Facebook 在內(nèi)的各大應(yīng)用紛紛采用了(相同的手勢(shì))。

當(dāng)這個(gè)特性出現(xiàn)在安卓端的 Chrome 瀏覽器中時(shí)王悍,問(wèn)題出現(xiàn)了:它會(huì)刷新整個(gè)頁(yè)面而不是加載更多的內(nèi)容破镰,成為開發(fā)者在他們的應(yīng)用中實(shí)現(xiàn)“下拉刷新”時(shí)的麻煩。

CSS 通過(guò) overscroll-behavior 這個(gè)新屬性解決問(wèn)題压储。它通過(guò)控制元素滾動(dòng)到盡頭時(shí)的行為來(lái)解決下拉刷新與連鎖滾動(dòng)所帶來(lái)的問(wèn)題鲜漩,(它的屬性值中)也包含針對(duì)不同平臺(tái)特殊值:安卓的 glow 與 蘋果系統(tǒng)中的 rubber band

現(xiàn)在集惋,上面 GIF 中的問(wèn)題孕似,在 Chrome、Opera 或 Firefox 中可以通過(guò)以下一行代碼來(lái)解決:

.element {
  overscroll-behavior: contain;
}

公平地說(shuō)刮刑,IE 與 Edge 實(shí)現(xiàn)了(它獨(dú)有的) -ms-scroll-chaining 屬性來(lái)控制連鎖滾動(dòng)鳞青,但它并不能處理所有的情況。幸運(yùn)的是为朋,根據(jù)這消息,微軟的瀏覽器已經(jīng)準(zhǔn)備實(shí)現(xiàn) overscroll-behavior 這一屬性了厚脉。

觸屏之后

觸屏設(shè)備上的滾動(dòng)(體驗(yàn))是一個(gè)很大的話題习寸,深入討論需要另開一篇文章。然而傻工,由于很多開發(fā)者忽略了這方面的內(nèi)容霞溪,這里需要提及一下孵滞。

(滾動(dòng)手勢(shì)無(wú)處不在,令人沉迷鸯匹,以至于想出了如此瘋狂的主意去解決“滾動(dòng)上癮”的問(wèn)題坊饶。)

周圍的人在智能手機(jī)屏幕上上下移動(dòng)他們的手指的頻率是多少呢?經(jīng)常這樣對(duì)吧殴蓬,當(dāng)你閱讀本文時(shí)匿级,你很可能就在這么做。

當(dāng)你的手指在屏幕上移動(dòng)時(shí)染厅,你期待的是:頁(yè)面內(nèi)容平滑且流暢地移動(dòng)痘绎。

蘋果公司開創(chuàng)了“慣性”滾動(dòng)并擁有它的專利 。它訊速地成為了用戶交互的標(biāo)準(zhǔn)并且我們對(duì)此已習(xí)以為常肖粮。

但你也許已經(jīng)注意到了孤页,盡管移動(dòng)端系統(tǒng)會(huì)為你實(shí)現(xiàn)頁(yè)面上的慣性滾動(dòng),但當(dāng)頁(yè)面內(nèi)某個(gè)元素發(fā)生滾動(dòng)時(shí)涩馆,即使用戶同樣期待慣性滾動(dòng)行施,但它并不會(huì)出現(xiàn),這令人沮喪魂那。

這里有一個(gè) CSS 的解決方案蛾号,但看起來(lái)更像是個(gè) hack:

.element {
  -webkit-overflow-scrolling: touch;
}

為什么這是個(gè) hack 呢?首先冰寻,它只能在支持(webkit)前綴的瀏覽器上才能工作须教。其次,它只適用于觸屏設(shè)備斩芭。最后轻腺,如果瀏覽器不支持的話,你就這樣置之不理嗎划乖?但無(wú)論如何贬养,這總歸是一個(gè)解決方案,你可以試著使用它琴庵。

在觸屏設(shè)備上误算,另一個(gè)需要考慮的問(wèn)題是開發(fā)者如何處理 touchstarttouchmove 事件觸發(fā)時(shí)可能存在的性能問(wèn)題,它對(duì)用戶滾動(dòng)體驗(yàn)的影響非常大迷殿。這里詳細(xì)描述了整個(gè)問(wèn)題儿礼。簡(jiǎn)單來(lái)說(shuō),現(xiàn)代的瀏覽器雖然知道如何使得滾動(dòng)變得平滑庆寺,但為確認(rèn)(滾動(dòng))事件處理函數(shù)中是否執(zhí)行了 Event.preventDefault() 以取消默認(rèn)行為蚊夫,有時(shí)仍可能需要花費(fèi)500毫秒來(lái)等待事件處理函數(shù)執(zhí)行完畢。

即使是一個(gè)空的事件監(jiān)聽器懦尝,從不取消任何行為知纷,鑒于瀏覽器仍會(huì)期待 preventDefault的調(diào)用壤圃,也會(huì)對(duì)性能造成負(fù)面影響。

為了準(zhǔn)確地告訴瀏覽器不必?fù)?dān)心(事件處理函數(shù)中)取消了默認(rèn)行為琅轧,在 WHATWG 的 DOM 標(biāo)準(zhǔn)中存在著一個(gè)不太顯眼的特性(能解決這問(wèn)題)伍绳。(它就是)Passive event listeners,瀏覽器對(duì)它的支持還是不錯(cuò)的乍桂。事件監(jiān)聽函數(shù)新接受一個(gè)可選的對(duì)象作為參數(shù)冲杀,告訴瀏覽器當(dāng)事件觸發(fā)時(shí),事件處理函數(shù)永遠(yuǎn)不會(huì)取消默認(rèn)行為模蜡。(當(dāng)然漠趁,添加此參數(shù)后,)在事件處理函數(shù)中調(diào)用 preventDefault 將不再產(chǎn)生效果忍疾。

element.addEventListener('touchstart', e => {
  /* doSomething */
}, { passive: true });

針對(duì)不支持該參數(shù)的瀏覽器闯传,這里也有一個(gè) polyfill 這視頻清晰地展示了此改進(jìn)帶來(lái)的影響卤妒。

舊技術(shù)運(yùn)行良好甥绿,為何還要改動(dòng)?

在現(xiàn)代互聯(lián)網(wǎng)中则披,過(guò)渡地依賴 JavaScript 在各瀏覽器上實(shí)現(xiàn)相同的交互效果不再是合理的共缕,“跨瀏覽器兼容性”已經(jīng)成為過(guò)去式,更多的 CSS 屬性與 DOM API 方法正逐步被各大瀏覽器所支持士复。

在我們看來(lái)图谷,當(dāng)你的項(xiàng)目中,有特別酷炫的滾動(dòng)效果時(shí)阱洪,漸進(jìn)增強(qiáng)是最好的做法便贵。

你應(yīng)該提供(給用戶)所有(你能提供的)基礎(chǔ)用戶體驗(yàn),并逐步在更先進(jìn)的瀏覽器上提供更好的體驗(yàn)冗荸。

必要時(shí)使用 polyfill承璃,它們不會(huì)產(chǎn)生(不必要的)依賴,一旦(某個(gè) polyfill 所支持的屬性)得到廣泛地支持蚌本,你就可以輕松地將它刪掉盔粹。

六個(gè)月之前,在本文尚未成文之時(shí)程癌,之前我們描述的屬性只被少量的瀏覽器所支持舷嗡。而到了本文發(fā)表之時(shí),這些屬性已被廣泛地支持嵌莉。

也許到了現(xiàn)在咬崔,當(dāng)你上下翻閱本文之時(shí),(之前不支持某些屬性的)瀏覽器已經(jīng)支持了該屬性,這使得你編程更容易垮斯,并使你的應(yīng)用打包出來(lái)體積更小。


感謝閱讀至此只祠!查閱瀏覽器的更新日志兜蠕,積極參與討論,有助于 web 標(biāo)準(zhǔn)駛向正確的方向抛寝。祝大家一帆風(fēng)順熊杨,順利滑(滾)向未來(lái)!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盗舰,一起剝皮案震驚了整個(gè)濱河市晶府,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钻趋,老刑警劉巖川陆,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蛮位,居然都是意外死亡较沪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門失仁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尸曼,“玉大人,你說(shuō)我怎么就攤上這事萄焦】亟危” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵拂封,是天一觀的道長(zhǎng)茬射。 經(jīng)常有香客問(wèn)我,道長(zhǎng)烘苹,這世上最難降的妖魔是什么躲株? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮镣衡,結(jié)果婚禮上霜定,老公的妹妹穿的比我還像新娘。我一直安慰自己廊鸥,他們只是感情好望浩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惰说,像睡著了一般磨德。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天典挑,我揣著相機(jī)與錄音酥宴,去河邊找鬼。 笑死您觉,一個(gè)胖子當(dāng)著我的面吹牛拙寡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琳水,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼肆糕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了在孝?” 一聲冷哼從身側(cè)響起诚啃,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎私沮,沒(méi)想到半個(gè)月后始赎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顾彰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年极阅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涨享。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筋搏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厕隧,到底是詐尸還是另有隱情奔脐,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布吁讨,位于F島的核電站髓迎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏建丧。R本人自食惡果不足惜排龄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翎朱。 院中可真熱鬧橄维,春花似錦、人聲如沸拴曲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)澈灼。三九已至竞川,卻和暖如春店溢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背委乌。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工床牧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遭贸。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓叠赦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親革砸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見瀏覽器兼容性問(wèn)題與解決方案糯累? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5算利? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 27,489評(píng)論 1 45
  • 1泳姐、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,982評(píng)論 3 119
  • 【回顧盤面】: 10月24日(周二)兩市小幅低開胖秒,之后滬指在持續(xù)橫盤整理至中午收盤缎患,而創(chuàng)業(yè)板則一路單邊下行;午后滬...
    齊利閱讀 316評(píng)論 0 21
  • 每個(gè)男兒都有一個(gè)軍營(yíng)夢(mèng)阎肝,熾熱而沸騰;每個(gè)經(jīng)歷過(guò)軍營(yíng)的男兒總是在一邊厭倦著一天又一天的重復(fù)刻板挤渔,而一邊又在離開時(shí)瘋狂...
    紅巧兒閱讀 367評(píng)論 0 1