免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
現(xiàn)代 JavaScript 與 CSS 令人著迷滾動(dòng)實(shí)現(xiàn)指南

一些(網(wǎng)站)滾動(dòng)的效果是如此令人著迷但你卻不知該如何實(shí)現(xiàn),本文將為你揭開(kāi)它們的神秘面紗。我們將基于最新的技術(shù)與規(guī)范為你介紹最新的 JavaScript 與 CSS 特性,(當(dāng)你付諸實(shí)踐時(shí),)將使你的頁(yè)面滾動(dòng)更平滑、美觀且性能更好。
css大家都很熟悉了,這里就不多介紹了。本文主要介紹一下兩個(gè)在日常的工作中可能會(huì)出錯(cuò)的地方。
大多數(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)往往是落后的。下文將為你介紹一些常見(jiàn)的關(guān)于滾動(dòng)的案例,檢查一下你所用的解決方案是否被更優(yōu)雅的方案所代替。

隱藏但可滾動(dòng)

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

body {  overflow: hidden;}

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

在這個(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ì)令開(kāi)發(fā)者發(fā)狂:

[圖片上傳失敗...(image-c423d3-1545732870735)]

注意,以上僅是 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í)際寬度):

onst 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 的。(為性能起見(jiàn),)如非必要,盡量避免進(jìn)行 DOM 操作。

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

tml {  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)條仍然是不可見(jiàn)的。滾動(dòng)條總是處于不可見(jiàn)狀態(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)條。

正如你所見(jiàn),并沒(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 的開(kāi)發(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)。

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

對(duì)于滾動(dòng)而言,最常見(jiàn)的任務(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é)果如下:


image

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


image

(平滑地滾動(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è)常見(jiàn)的需求是根據(jù)滾動(dòng)方向動(dòng)態(tài)地定住元素,即有名的“粘性(即 CSS 中的position: sticky)”效應(yīng)。


image

(一個(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í)

不久之前,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)聽(tīng)器 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)聽(tīng)函數(shù),(節(jié)流函數(shù)是)減少被包裝函數(shù)的執(zhí)行次數(shù),只允許它在固定的時(shí)間間隔之內(nèi)執(zhí)行一次:

ction 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é)流:

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

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

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

在視窗中顯示

當(dāng)你需要實(shí)現(xiàn)圖片懶加載或者無(wú)限滾動(dòng)時(shí),需要確定元素是否出現(xiàn)在視窗中。這可以在事件監(jiān)聽(tīng)器中處理,最常見(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);

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

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


image

(連鎖滾動(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)容,成為開(kā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è)很大的話題,深入討論需要另開(kāi)一篇文章。然而,由于很多開(kāi)發(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)。

蘋果公司開(kāi)創(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)題是開(kāi)發(fā)者如何處理 touchstart 與 touchmove 事件觸發(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)聽(tīng)器,從不取消任何行為,鑒于瀏覽器仍會(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)聽(tīng)函數(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 });

舊技術(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)體積更小。

前端學(xué)習(xí)圈

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
WebStorm 2022(Web前端開(kāi)發(fā)工具) v2022.3.2中文Mac版
前端開(kāi)發(fā)面試題 | 菜鳥(niǎo)教程
Web前端面試題目及答案匯總 – 碼農(nóng)網(wǎng)
前端工程師面試題匯總
前端頁(yè)面性能優(yōu)化
測(cè)試你的前端代碼 – part3(端到端測(cè)試)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服