探究 position-sticky 失效問題

CSS 的 position 值中,有一個非常有用的值 — position: sticky,通常會被用於各種吸頂,吸底,吸邊的效果中。

如果你對 sticky 還不太熟悉,可以先看看我的這篇文章:使用 position:sticky 實現粘性布局,當然,這篇文章裏面有稍微探討 position: sticky 生效或者說失效的規則,但是不太充分。

最近遇到一些 position-sticky 失效的場景,所以總結了一下。

 

position-sticky 生效的原理

在 W3 官方文檔中的定義是:Sticky positioning is similar to relative positioning except the offsets are automatically calculated in reference to the nearest scrollport.

轉換成通俗的大白話就是,Sticky 定位類似於相對定位,(當它表現為 fixed 定位的特性時)會根據最近的滾動容器(nearest scrollport)自動計算偏移量。

其中有一個非常重要的概念就是 nearest scrollport,它表示 sticky 元素在即將消失前會相對它最近的 scrollport 去做定位。 

 

正常的 DEMO

所以正常而言,類似下面的這種情況,sticky 是可以正常展示的。

<div class="container"> - 可滾動的容器 scrollport     
    <div class="sticky">   - 設置了 sticky 的元素

CodePen Demo — Normal Sticky Demo 

失效的 position: sticky

1、包裹的父容器高度與 sticky 元素一致

有趣的是,如果在 .sticky 元素和你希望 .sticky 生效吸附的滾動元素中間,添加上一層 .parent 的 div 元素,不給 div 添加任何樣式,sticky 則失效了。

譬如是這樣:

<div class="container">      - 可滾動的容器 scrollport     
    <div class="parent"> 
         <div class="sticky">   - 設置了 sticky 的元素

CodePen Demo — invalid Sticky Demo 1

失效原因:此時 .sticky 元素的最近的 scrollport 變成了它的父容器 div,而父容器 div 的高度和 .sticky 元素的高度是一樣的,所以表現不出 fixed 的特性。

其實,這裡不算失效,我們只需要將包裹 .sticky 元素的父容器的高度設置的大於 .sticky 元素本身,也能看到效果。

譬如,我們可以加上

.parent {
    height: 100vh;
}

此時,sticky 將重新生效,像是這樣:

其實,造成這種現象的本質原因是,設置了 position: sticky 的元素吸附的基準元素從 .container 變成了 .parent 。

 

2、包裹的父容器設置了 overflow: hidden

第二種情況,也會導致 position: sticky 的 fixed 定位特性失效。也就是 .sticky 元素的祖先容器存在 overflow: hidden。類似這樣

<div class="container">      - 可滾動的容器 scrollport     
    <div class="hidden">      - 設置了 overflow: hidden
         <div class="sticky">   - 設置了 sticky 的元素

CodePen Demo — invalid Sticky Demo 2

在上面這個 DEMO 裏面,設置了 sticky 的元素的父元素 hidden 元素,它的高度是遠比 stikcy 元素高的,但是滾動的過程中卻沒有表現出 fixed 的特性。

原因在於,設置了 overflow: hidden 的元素,它不再代用滾動的特性,當 sticky元素吸附於.hidden元素的頂部時,它隨着 .hidden` 元素本身在 container 移動。所以,所有的 sticky 元素都會被滾動出 container 的滾動區域。

當然,這裡有一點比較奇怪的是,.sticky 元素相對 .hidden 元素進行 fixed 定位,而不是相對 .container 元素進行 fixed 定位,表面設置了 overflow: hidden 的元素,它也是一個 scrollport。

其實,不止是 overflow: hidden ,設定為 position: sticky 元素的任意父節點的 overflow 屬性必須是 visible,否則 position:sticky 不會生效。

 

總結一下

看完上面幾個 DEMO,可以好好總結一下 position:sticky 的生效規則,明白了生效規則就會知道為什麼有的時候設定的 sticky 會失效:

  1. 須指定 top, right, bottom 或 left 四個閾值其中之一(且達到設定的閾值),才可使粘性定位生效。否則其行為與相對定位相同;
    • 並且 top 和 bottom 同時設置時,top 生效的優先級高,left 和 right 同時設置時,left 的優先級高
  2. 設定為 position: sticky 的元素的任意父節點的 overflow 屬性必須是 visible,否則 position:sticky 不會生效;在滿足上述情況下,設定了 position: sticky 的元素的父容器的高度必須大於當前元素,否則也會失效。(當然,此時,sticky 吸附的基準元素就會變成父元素)
    • 如果 position: sticky 元素的任意父節點定位設置為 position: overflow,則父容器無法進行滾動,所以 position:sticky 元素也不會有滾動然後固定的情況
  3. 在滿足上述情況下,設定了 position: sticky 的元素的父容器的高度必須大於當前元素,否則也會失效。(當然,此時,sticky 吸附的基準元素就會變成父元素)

 

最後

好了,本文到此結束。

更多精彩 CSS 技術文章匯總在我的 Github — iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

Tags: