首頁 > 科技

減少 JavaScript 程式碼量的原生技術

2021-06-11 05:36:50

作者 | Anthony Ricaud

譯者 | 彎月 責編 | 歐陽姝黎

以下為譯文:

如今依賴 JavaScript 提供互動的網站越來越多。雖然 JavaScript 可以提供愉快的體驗,但同時也帶來了一些負面影響:

  • 頁面載入時間變長;

  • 只有在 JavaScript 載入完成且正確無誤後,頁面才能使用;

  • 團隊需要足夠的手段和資源來關注可用性、反應性和可訪問性。

鑑於這些缺點,我們可以依靠瀏覽器提供的原生解決方案,這種方式不僅可以降低成本,而且還可以享受社群創建的 Web 標準專業知識帶來的優勢。通常,這些解決方案的程式碼量較少,因此還可以減少開發團隊的維護工作(比如無需更新使用的庫)。

在本文中,我們來探討一下部分可供大多數使用者使用的原生解決方案。我會給出一些示例,但不會深入探討所有細節。

渲染被 JavaScript 阻塞

在介紹各種技術之前,首先我需要提醒一下使用 JavaScript 的一大缺點:瀏覽器只有一個執行緒來控制頁面的渲染。在運行 JavaScript 時,瀏覽器會延遲使用者互動事件與介面更新。這就很討厭了,因為你會覺得頁面沒有響應你的操作,或者感覺動畫很卡。谷歌工程師 Philip Walton 對這方面優化進行了詳細闡述,感興趣可以前往檢視:https://calendar.perfplanet.com/2020/html-and-css-techniques-to-reduce-your-javascript/

開發團隊的日常工作比較喜歡功能強大的裝置,因此會掩蓋 JavaScript 帶來的負面影響。但不要忘記在功能有限的裝置上做定期測試。

限制顯示的行數

JavaScript版

以下是用JavaScript實現此操作的兩種方法:

  1. 限制顯示的字元數。這種做法很容易出錯,因為除了等寬字型之外,一般字型的寬度都是可變的。因此,最終顯示出來的文字長度往往會超過預期,或被中途截斷。

  2. 反覆試驗元素顯示的內容,直到達到理想的行數。這種做法的代價很高,因為每次嘗試都需要瀏覽器完成渲染,才能看清顯示的內容。而且這種技術只有在使用指定字型渲染後才能得到準確的結果,這可能會導致較大的佈局偏移。

當頁面包含大量需要截斷的文字時,頁面顯示會被延遲。此外,這兩種解決方案會完全截斷文字,有可能會影響到搜尋引擎或輔助技術的恢復。頁面中元素的字型大小或寬度也有可能發生變化。考慮所有的情況很麻煩。

原生版

-webkit-line-clamp 是一個原生的 CSS 屬性。十年前在 Safari 中引入,如今已被廣泛使用,其他瀏覽器出於相容性原因也採用了這個屬性,而且已成了標準。你需要一些其他帶字首的屬性來實現所需的行為。雖然使用帶有字首的屬性性有點煩人,但是標準中已經詳細描述了該字首,因此這樣做不會有風險。

除了 IE 和 Firefox 68 之前的版本外,所有瀏覽器都支援該屬性。下面的例子說明了具體的使用方式。

HTML :

<div class="demo-grid">
<div class="demo-card">
<img width="200" height="200" src="https://placekitten.com/200/200?image=1" alt="" class="demo-img">
<h1 class="line-clamp demo-title">
Spill litter box, scratch at owner, destroy all furniture, especially couch
</h1>
</div>

<div class="demo-card">
<img width="200" height="200" src="https://placekitten.com/200/200?image=2" alt="" class="demo-img">
<h1 class="line-clamp demo-title">
Claws in the eye of the beholder
</h1>
</div>

<div class="demo-card">
<img width="200" height="200" src="https://placekitten.com/200/200?image=3" alt="" class="demo-img">
<h1 class="line-clamp demo-title">
Relentlessly pursues moth eat too much then proceed to regurgitate all over living room carpet while humans eat dinner
</h1>
</div>
</div>
<!-- Titles via http://www.catipsum.com/ -->

CSS:

/* By default, truncate the text abruptly */
.line-clamp {
/* Careful computing the max-height, it needs to match n * line-height */
max-height: calc(2 * 1.15 * 1.5rem);
overflow: hidden;
}

/* For capable browsers, truncate with an ellipsis */
/* To simulate a browser without support, you can add a s after clamp in the following line */
@supports (-webkit-line-clamp: 2) {
.line-clamp {
/* Remove the made up max-height */
max-height: none;

/* Those three properties are mandatory, so is overflow: hidden that we defined earlier */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}


/* Extra code for the look of the demo */
.demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(13rem,1fr));
gap: 1rem;
margin: 1rem;
}
.demo-card {
background-color: #E2E8F0;
border-radius: 0.5rem;
display: flex;
flex-direction: column;
padding: 0.5rem;
}
.demo-img {
align-self: center;
margin-bottom: 0.5rem;
border-radius: 0.5rem;
}
.demo-title {
font-size: 1.5rem;
margin: 0;
}
View Compiled


Resources

該解決方案沒有效能或頁面內容偏移的問題,而且還不會影響搜尋引擎或輔助技術。但是,它不適合擁有多個子項的元素。

重要的元素始終顯示在頁面上

有時候,你希望頁面的某個部分始終顯示在視野範圍內,比如標題、工具欄或購物車。我經常遇到這種行為,但能夠正確實現的卻很少。

JavaScript 版

如果想通過 JavaScript 實現這個功能,則必須監聽頻繁觸發的滾動事件。大多數解決方案經常會通過限流或去抖動的技術去除大部分事件。現如今,我們可以使用 IntersectionObserver,僅在元素進入或離開視窗時接收事件。這樣做的效率更高。

在檢測到元素進入或離開視窗時,我們需要從 position:relative 切換到 position:fixed。這需要瀏覽器重新計算大量元素的大小和位置(我們稱之為頁面重新佈局),這種做法的代價很大。我們需要確保周圍元素不會四處移動,而且不會導致內容跳躍。

如果在元素進入或退出視窗時,渲染被阻塞(如果在滾動的同時協調使用動畫,則很可能發生阻塞),那麼切換將被進一步延遲。

原生版

CSS 有一個屬性position:sticky 可以實現這種行為,而且還沒有效能、響應性或內容跳躍的問題:只要瀏覽器可以滾動,它就會將元素準確地定位到你聲明的位置上。你可以利用top、bottom、left或right選擇定位。

html

CSS

除了IE和舊版的 Chrome 或 Firefox 之外,所有瀏覽器都支援sticky。對於這些舊版的瀏覽器,元素僅支援預設值 position:static,而且不會處理 top、bottom、left 和 right 的值。如果你需要支援這些瀏覽器,則請記住這一點。舊版的 Safari 需要 -webkit-sticky 字首。

但是,這個屬性有一個限制:無法根據元素是否sticky來改變元素的外觀,比如使用:stuck之類的偽類。這是 CSS常見的限制。在這種情況下,我建議使用 position:sticky 來設定sticky屬性,同時結合 IntersectionObserver來改變其外觀(注意不要改變大小,以防止內容跳躍)。

平滑滾動

JavaScript 版

如果想在JavaScript中實現這一點,你需要定期執行改變滾動位置的JavaScript。為了動畫能夠流暢地運行,在整個動畫運行過程中,不能有其他JavaScript阻塞渲染。

此外,你還需要選擇一個計時函數。為了看起來很自然,可能需要針對每個作業系統使用不同的計時函數,才能符合該作業系統的常規做法。

原生版

CSS有一個屬性scroll-behavior: smooth和{behavior: 'smooth'},可以代替JavaScript的scroll、scrollTo和scrollIntoView,將所有有關計時的決定都交給CSS。這樣可能更符合常用裝置的常規做法。

Safari 尚不支援此功能(除非啟用隱藏選項),但大多數情況下,這不是什麼大問題。

html

CSS

無論是JavaScript版還是原生版,你都需要注意兩個可訪問性方面的問題:遵循儘可能減少動畫和頁面移動的設定,以及確保焦點正確移動。

滾動到吸附點

通過這種方式,可以創建幻燈片、水平列表,吸附到每張圖片或每一節,讓它們佔據整個視窗。

JavaScript版

為了創建幻燈片,我們需要監聽:

  • 滑鼠點選事件(mousedown、mouseup、touchstart、touchend、pointerdown 或 pointerup);

  • 移動事件(mousemove、touchmove 或 pointermove)。

正確處理所有指針事件(滑鼠事件或觸碰事件),並處理滑鼠指針離開區域的事件非常需要技巧。如果能正確處理這些事件,就可以相應地移動元素。每次移動都可能導致昂貴的重新佈局,破壞顯示效果。

如果每一節都佔據整個視窗或遇到水平列表,我們必須監聽所有滾動事件,並用我們需要的滾動處理替換。獲得理想的效果非常困難,因為我們需要完整地控制原生的滾動行為。

不論何種情況,你都需要根據原始的頁面移動速度和距離來確定是否應該移動到下一個項目。如果你的選擇不符合系統的行為,就會給使用者造成困擾。

原生版

CSS的滾動吸附功能可以處理該行為。在滾動的容器中,定義scroll-snap-type來指示吸附的方向,以及吸附必定發生還是僅在接近吸附點時發生。然後在容器的子元素中定義scroll-snap-align來標明吸附點。

下面的演示完全沒有使用JavaScript。它還使用了scroll-behavior來提示使用者使用正常的滾動機制。

選中複選框,即可使用IntersectionObserver在縮圖中高亮顯示當前的圖片。

html

CSS

JS

所有現代瀏覽器都支援該行為。還有另一種語法(https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap/Browser_compat)但我不建議使用。它只會增加測試的負擔,而你可以依靠優雅降級來解決該問題。在不支援滾動吸附的瀏覽器中,該功能將會降級為正常的滾動。

不論對於滑鼠的情況還是觸控式螢幕的情況,由於使用了瀏覽器的滾動功能,該方法要比JavaScript的方法流暢許多。

延遲影象載入

JavaScript版

用JavaScript實現該功能需要使用類似於<img data-src="..." data-srcset="..." alt="...">的語法。當影象接近視口時,使用Javascript改變影象的屬性,以載入並顯示圖片。

這種方法的主要缺點就是,在相應的JavaScript執行之前影象不會被顯示。而且這種情況發生的頻率遠超你的想象。搜尋引擎也很難看到影象,因為本質上影象並不存在,而且爬蟲也不會滾動螢幕。

選擇何時觸發載入非常重要。怎樣根據當前的頻寬來決定當影象距離視口多遠時進行載入?是否應當考慮滾動的速度?

原生版

去年,所有瀏覽器(Safari除外)都實現了<img>元素的loading="lazy"屬性。如果你的網站會載入所有影象,那麼可以嘗試下這個屬性。幾乎不需任何代價,就可以讓網站載入變快。

如果你已經使用了某種延遲載入技術,那麼在Safari支援該屬性之前,你需要根據自己的情況做決定。是否值得放棄Safari的延遲載入,來換取更簡單的程式碼?

目前,觸發下載的規則由各個瀏覽器決定,可能不是最佳時機。不過有一點可以確定,瀏覽器的決定會越來越理想,而不需要改變任何程式碼!

總結

我希望這篇文章可以給你一些啟示,下次在尋找某個 JavaScript 庫來實現某項功能時,可以考慮一下這些技術。此外,你也可以看看其他我沒有提及的 HTML 或 CSS 技術(比如<details>和<summary>,或<datalist>)。瀏覽器在不斷髮展,會不斷帶來驚喜,使用者也會受益!

原文連結:https://calendar.perfplanet.com/2020/html-and-css-techniques-to-reduce-your-javascript/

聲明:本文由CSDN翻譯,轉載請註明來源。


IT145.com E-mail:sddin#qq.com