使用 position:sticky 實現粘性佈局
如果問,CSS 中 position 屬性的取值有幾個?
大部分人的回答是,大概是下面這幾個吧?
123456 | {position:static;position:relative;position:absolute;position:fixed;} |
額,其實,我們還可以有這 3 個取值:
123456 | {/* 全域性值 */position:inherit;position:initial;position:unset;} |
沒了嗎?偶然發現其實還有一個處於實驗性的取值,position:sticky
123 | {position:sticky;} |
臥槽,什麼來的?
前端發展太快,新東西目接不暇,但是對於有趣的東西,還是忍不住一探究竟。(只怪當初…)
初窺 position:sticky
sticky 英文字面意思是粘,貼上,所以姑且稱之為粘性定位。下面就來了解下這個處於實驗性的取值的具體功能及實用場景。
這是一個結合了 position:relative
position:fixed
兩種定位功能於一體的特殊定位,適用於一些特殊場景。
什麼是結合兩種定位功能於一體呢?
元素先按照普通文件流定位,然後相對於該元素在流中的 flow root(BFC)和 containing block(最近的塊級祖先元素)定位。
而後,元素定位表現為在跨越特定閾值前為相對定位,之後為固定定位。
這個特定閾值指的是 top, right, bottom 或 left 之一,換言之,指定 top, right, bottom 或 left 四個閾值其中之一,才可使粘性定位生效。否則其行為與相對定位相同。
不樂觀的相容性
在講述具體示例之前,還是很有必要了解一下 position:sticky
的相容性,嗯,不樂觀的相容性。
SHIT,這麼好的屬性支援性居然這麼慘淡。
IOS 家族(SAFARI && IOS SAFARI)和 Firefox 很早開始就支援 position:sticky
了。而 Chrome53~55 則需要啟用實驗性網路平臺功能才行。其中 webkit 核心的要新增上私有字首 -webkit-
。
Chrome53~55 開啟實驗性網路平臺功能
位址列輸入 chrome://flags/
,找到 enable-experimental-web-platform-features
,選擇啟用:
所以下面的 CodePen 示例,需要上述幾個瀏覽器下觀看。
position:sticky
示例
嗯,上面的文字描述估計還是很難理解,看看下面這張 GIF 圖,想想要實現的話,使用 JS + CSS 的方式該如何做:
按照常規做法,大概是監聽頁面 scroll 事件,判斷每一區塊距離視口頂部距離,超過了則設定該區塊 position:fixed
,反之去掉。
而使用 position:sticky
,則可以非常方便的實現(請在 SAFARI 或者 CHROME53+ 下觀看):
嗯,看看上面的 CSS 程式碼,只需要給每個內容區塊加上
12345 | {position:-webkit-sticky;position:sticky;top:0;} |
就可以輕鬆實現了。
簡單描述下生效過程,因為設定的閾值是 top:0
,這個值表示當元素距離頁面視口(Viewport,也就是fixed定位的參照)頂部距離大於 0px 時,元素以 relative 定位表現,而當元素距離頁面視口小於 0px 時,元素表現為 fixed 定位,也就會固定在頂部。
不理解可以再看看下面這兩張示意圖(top:20px 的情況,取自開源專案fixed-sticky):
距離頁面頂部大於20px,表現為 position:relative
;
距離頁面頂部小於20px,表現為 position:fixed
;
運用 position:sticky
實現頭部導航欄固定
運用 position:sticky
實現導航欄固定,也是最常見的用法:
(請在 SAFARI 或者 CHROME53+ 下觀看):
同理,也可以實現側邊導航欄的超出固定。
生效規則
position:sticky
的生效是有一定的限制的,總結如下:
- 須指定 top, right, bottom 或 left 四個閾值其中之一,才可使粘性定位生效。否則其行為與相對定位相同。
- 並且
top
和bottom
同時設定時,top
生效的優先順序高,left
和right
同時設定時,left
的優先順序高。
- 並且
- 設定為
position:sticky
元素的任意父節點的 overflow 屬性必須是 visible,否則position:sticky
不會生效。這裡需要解釋一下:- 如果
position:sticky
元素的任意父節點定位設定為overflow:hidden
,則父容器無法進行滾動,所以position:sticky
元素也不會有滾動然後固定的情況。 - 如果
position:sticky
元素的任意父節點定位設定為position:relative | absolute | fixed
,則元素相對父元素進行定位,而不會相對 viewprot 定位。
- 如果
- 達到設定的閥值。這個還算好理解,也就是設定了
position:sticky
的元素表現為relative
還是fixed
是根據元素是否達到設定了的閾值決定的。
開始使用?
上面從相容性也看到了,情況不容樂觀,但是用於某些佈局還是能省很多力的,如果真的希望用上這個屬性,可以採用一些開源庫來實現相容。
系列 CSS 文章彙總在我的 Github 。
到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式