CSS Sticky 其實很簡單

爲何要寫這篇文章

Sticky 也不是新知識點了,寫這篇文章的緣由是因爲最近在實現效果的過程當中,發現我對 Sticky 的理解有誤差,代碼執行結果不如預期。決定寫篇文章從新學習一次。css

什麼是 Sticky

Sticky (MDN 翻譯成粘性效果)是 CSS 屬性 position 中的一個可選值。跟咱們用得比較多的 static, fixedrelativeabsolute 同樣,用來描述元素的定位方式。html

從效果上看,Sticky 像是混合體,頁面滑動到「臨界點」以前表現爲 relative, 到達「臨界點」時表現爲 fixedreact

 

 

如何使用

使用 CSS Sticky 只須要兩個條件。git

position: sticky;
top: 0; // right/bottom/left 任一有效值,甚至能夠爲負像素值
複製代碼

top:0 意思是當元素滑動到距離視口 0px 時再繼續滑動,元素吸頂。能夠在 這裏 看效果(試試看修改 top 值)github

對比 JS 的實現方案

沒有 CSS Sticky 以前,相似的效果都是使用 JS 實現。大體步驟以下:npm

  1. 監聽滾動事件,計算目標元素距離視口的距離。
  2. 距離不知足條件時,按兵不動。
  3. 距離知足條件時,建立佔位元素,修改目標元素定位方式爲 fixed
window.addEventListener('scroll', () => { const rect = elem.getBoundingClientRect(); // 計算目標元素和視口的距離 }) 複製代碼

在 npm 上搜 sticky 關鍵字,也有不少優秀的包可使用。以 react-sticky 爲例,知足條件時會建立 placeholder 元素(防止頁面抖動),同時讓 header 定位爲 fixedapp

React Sticky

 

右邊是 Chrome Dev-Toolslayers 面板,藍色部分爲生成的 placeholderpost

 

兩種方案的火焰圖對比(爲了放大效果,我把 cpu 調慢了 6 倍)學習

CSS 方案

 

css 方案

 

使用 CSS Sticky,工做都交給 GPU 了,不佔用 JS 主線程的資源,在移動端上異常流暢。spa

React Sticky

 

React Sticky 方案

 

因爲須要在 scroll event 回調中不斷調用 getBoundingClientRect,而 getBoundingClientRect 又會觸發頁面重排重繪,稍不留神就掉幀卡頓。僅僅爲了實現這個效果(頁面上沒有其餘內容)大動干戈性價比很低。

結論是:實現 Sticky 效果,優先選擇 CSS Sticky

理解上的誤差

1. 只在 Containing Block 內有效。

修改例子,用一個 div 把 Sticky Header 包裹起來,發現 Sticky 效果失效了!!!

...
  <div class="wrapper"> <header>Sticky Header</header> </div> ... 複製代碼

根據文檔,Sticky 效果只在 Containing Block 內有效,Containing Block 滑出屏幕時,Stickey Element 也跟着滑走。

修改 wrapper 的高度,看效果。

.wrapper { height: 100px; background-color: #e6e6e6; } 複製代碼

 

 

多個 Sticky Element 放在一塊就有了前一個被後一個頂出去的特效,實際上並非真的被頂出去,而是 Containing Block 把它拖走。

 

 

代碼看這裏

2. Overflow 會影響 Sticky

修改例子中的代碼,給 #root 加上 overflow: auto

#root { overflow: auto; } 複製代碼

Sticky 效果再次丟失(overflow 設置爲其餘非 visible 的有效值也是一樣效果。)

看了不少相關的文檔,個人出來的結論是:

Sticky Element 的 offset 值是依據 nearest scrolling ancestor (距離最近的滾動祖先) 計算的,若是沒有匹配上的祖先元素,則使用視口做爲參照物。

問題就出在 overflow-x 或者 overflow-y 其中任一爲非 visible 則認爲是要找的目標元素,而在滾動窗口的過程當中,Sticky Element 和 它找到的目標祖先元素的 offset 值一直沒有改變,因此 Sticky 不起做用。

對症下藥,讓滾動發生在被「誤匹配」上的祖先元素內便可恢復 Sticky Effect

#root { overflow: auto; height: 100vh; } 複製代碼

兼容性

算上 prefixed ,當前 css sticky 手機端兼容性達到 94.14%,若是你所作的業務須要照顧剩下 5.86% 的用戶,也可使用 polyfill 或者 position: fixed

 

caniuse sticky

 

相關連接

做者:HelKyle 連接:https://juejin.im/post/5cde75636fb9a07ef562048a 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索