如何獲得粘性和全溢的元素來很好地發揮作用
最近我遇到一個獨特的佈局需求:在頁麵包含全屏元素的同時,保持一個元素始終固定在頂部。這實現起來相當棘手,因此我將記錄下我的解決方案,以備不時之需。尤其是在小屏幕上的邏輯定位處理上,更是增加了難度。
效果難以用文字描述,所以我錄製了屏幕視頻來說明我的意思。請特別注意主要的號召性用語部分,也就是帶有“立即體驗Domino”標題的部分。
我們的目標是在較大視窗中,將主要的號召性用語顯示在右側,而用戶向下滾動時,其他部分會從其下方經過。在較小視窗中,號召性用語元素必須顯示在帶有“開始試用”標題的主要英雄區之後。
這裡主要有兩個挑戰:
- 創建不與粘性元素衝突的全屏元素
- 避免重複HTML代碼
在深入探討幾種可能的解決方案(及其局限性)之前,讓我們先搭建語義化的HTML結構。
HTML結構
構建此類佈局時,可能會傾向於創建重複的號召性用語部分:一個用於桌面版本,另一個用於移動版本,然後在適當的時候切換它們的可見性。這避免了在HTML中尋找完美位置以及應用處理兩種佈局需求的CSS的麻煩。我必須承認,我有時也會這樣做。但這一次,我想避免重複我的HTML代碼。
另一個需要考慮的是,我們對.box--sticky
元素使用了粘性定位,這意味著它需要與其他元素(包括全屏元素)同級,才能正常工作。
以下是標記:
<div> <div>英雄區</div> <div>粘性區</div> <div>全屏區</div> <div>全屏區</div> </div>
創建粘性元素
在CSS網格佈局中創建粘性元素非常簡單。我們向.box--sticky
元素添加position: sticky
和top: 0
偏移量,指示其開始粘貼的位置。注意,我們只在視窗寬度大於768px時才使元素粘性化。
@media screen and (min-width: 768px) { .box--sticky { position: sticky; top: 0; } }
需要注意的是,當position: sticky
與overflow: auto
一起使用時,Safari中存在已知的粘性定位問題。 Caniuse網站的已知問題部分對此進行了說明:
設置為
overflow: auto
的父元素會阻止Safari中position: sticky
的工作。
不錯,這很容易。接下來讓我們解決全屏元素的挑戰。
方案一:偽元素
第一個方案是我經常使用的方法:絕對定位的偽元素,可以從一側延伸到另一側。這裡的技巧是使用負偏移量。
如果我們討論的是居中內容,那麼計算就相當簡單:
.box--bleed { max-width: 600px; margin-right: auto; margin-left: auto; padding: 20px; position: relative; } .box--bleed::before { content: ""; background-color: dodgerblue; position: absolute; top: 0; bottom: 0; right: calc((100vw - 100%) / -2); left: calc((100vw - 100%) / -2); }
簡而言之,負偏移量是視窗寬度( 100vw
)減去元素寬度( 100%
),然後除以-2,因為我們需要兩個負偏移量。
需要注意的是,使用100vw
時存在一個已知的bug,Caniuse網站也對此進行了說明:
目前除Firefox之外的所有瀏覽器都錯誤地認為
100vw
是整個頁面寬度,包括垂直滾動條,當設置overflow: auto
時,這可能會導致水平滾動條。
現在讓我們在內容不居中的情況下創建全屏元素。如果你再次觀看視頻,你會注意到粘性元素下方沒有內容。我們不希望粘性元素與內容重疊,這就是為什麼在這個特定的佈局中沒有居中內容的原因。
首先,我們將創建網格:
.grid { display: grid; grid-gap: var(--gap); grid-template-columns: var(--cols); max-width: var(--max-width); margin-left: auto; margin-right: auto; }
我們使用自定義屬性,允許我們重新定義最大寬度、間隙和網格列,而無需重新聲明屬性。換句話說,我們重新聲明變量值,而不是重新聲明grid-gap
、 grid-template-columns
和max-width
屬性:
:root { --gap: 20px; --cols: 1fr; --max-width: calc(100% - 2 * var(--gap)); } @media screen and (min-width: 768px) { :root { --max-width: 600px; --aside-width: 200px; --cols: 1fr var(--aside-width); } } @media screen and (min-width: 980px) { :root { --max-width: 900px; --aside-width: 300px; } }
在寬度為768px及以上的視窗上,我們定義了兩列:一列具有固定寬度( --aside-width
),另一列填充剩餘空間( 1fr
),以及網格容器的最大寬度( --max-width
width )。
在小於768px的視窗上,我們定義了一列和間隙。網格容器的最大寬度是視窗的100%,減去兩側的間隙。
現在是精彩的部分。內容在較大的視窗上沒有居中,因此計算不像你想像的那麼簡單。以下是它的樣子:
.box--bleed { position: relative; z-index: 0; } .box--bleed::before { content: ""; display: block; position: absolute; top: 0; bottom: 0; left: calc((100vw - (100% var(--gap) var(--aside-width))) / -2); right: calc(((100vw - (100% - var(--gap) var(--aside-width))) / -2) - (var(--aside-width))); z-index: -1; }
我們沒有使用父元素寬度的100%,而是考慮了間隙和粘性元素的寬度。這意味著全屏元素中的內容寬度不會超過英雄元素的邊界。這樣,我們確保粘性元素不會與任何重要信息重疊。
左側偏移量比較簡單,因為我們只需要從視窗寬度( 100vw
)中減去元素寬度( 100%
)、間隙( --gap
)和粘性元素( --aside-width
)。
left: (100vw - (100% var(--gap) var(--aside-width))) / -2);
右側偏移量比較複雜,因為我們必須將粘性元素的寬度添加到之前的計算中, --aside-width
,以及間隙, --gap
:
right: ((100vw - (100% var(--gap) var(--aside-width))) / -2) - (var(--aside-width) var(--gap));
現在我們可以確保粘性元素不會與全屏元素中的任何內容重疊。
這是一個包含水平bug的解決方案:
這是一個包含水平bug修復的解決方案:
修復方法是隱藏body的x軸溢出,這通常也是一個好主意:
body { max-width: 100%; overflow-x: hidden; }
這是一個完全可行的解決方案,我們可以在此結束。但這有什麼樂趣呢?通常不止一種方法可以完成某件事,所以讓我們看看另一種方法。
方案二:填充計算
我們可以通過配置網格來實現相同的效果,而不是使用居中的網格容器和偽元素。讓我們從定義網格開始,就像我們上次做的那樣:
.grid { display: grid; grid-gap: var(--gap); grid-template-columns: var(--cols); }
同樣,我們使用自定義屬性來定義間隙和模板列:
:root { --gap: 20px; --gutter: 1px; --cols: var(--gutter) 1fr var(--gutter); }
我們在小於768px的視窗上顯示三列。中間列佔據盡可能多的空間,而另外兩列僅用於強制水平間隙。
@media screen and (max-width: 767px) { .box { grid-column: 2 / -2; } }
請注意,所有網格元素都放置在中間列中。
在大於768px的視窗上,我們定義了一個--max-width
變量,它限制了內部列的寬度。我們還定義了--aside-width
,即粘性元素的寬度。同樣,這樣可以確保粘性元素不會定位在全屏元素內的任何內容之上。
:root { --gap: 20px; } @media screen and (min-width: 768px) { :root { --max-width: 600px; --aside-width: 200px; --gutter: calc((100% - (var(--max-width))) / 2 - var(--gap)); --cols: var(--gutter) 1fr var(--aside-width) var(--gutter); } } @media screen and (min-width: 980px) { :root { --max-width: 900px; --aside-width: 300px; } }
接下來,我們將計算邊距寬度。計算公式是:
--gutter: calc((100% - (var(--max-width))) / 2 - var(--gap));
…其中100%
是視窗寬度。首先,我們從視窗寬度中減去內部列的最大寬度。然後,我們將結果除以2以創建邊距。最後,我們減去網格間隙以獲得邊距列的正確寬度。
現在讓我們將.box--hero
元素推到一邊,以便它從網格的第一列開始:
@media screen and (min-width: 768px) { .box--hero { grid-column-start: 2; } }
這會自動推動粘性框,使其緊跟在英雄元素之後。我們也可以明確地定義粘性框的位置,如下所示:
.box--sticky { grid-column: 3 / span 1; }
最後,讓我們通過將grid-column
設置為1 / -1
來創建全屏元素。這告訴元素從第一個網格項開始內容,並跨越到最後一個網格項。
@media screen and (min-width: 768px) { .box--bleed { grid-column: 1 / -1; } }
為了居中內容,我們將計算左側和右側填充。左側填充等於邊距列的大小加上網格間隙。右側填充等於左側填充的大小,再加上另一個網格間隙以及粘性元素的寬度。
@media screen and (min-width: 768px) { .box--bleed { padding-left: calc(var(--gutter) var(--gap)); padding-right: calc(var(--gutter) var(--gap) var(--gap) var(--aside-width)); } }
這是最終的解決方案:
我更喜歡這個解決方案,因為它沒有使用有問題的視窗單位。
我喜歡CSS計算。使用數學運算並不總是直截了當的,尤其是在組合不同的單位時,例如100%
。弄清楚100%
的含義是工作的一半。
我也喜歡使用CSS解決簡單但複雜的佈局,就像這個一樣。現代CSS具有原生解決方案——例如網格、粘性定位和計算——消除了複雜且相當繁重的JavaScript解決方案。讓我們把臟活留給瀏覽器吧!
你對此有更好的解決方案或不同的方法嗎?我很樂意聽到你的想法。
以上是如何獲得粘性和全溢的元素來很好地發揮作用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

您是否曾經在項目上需要一個倒計時計時器?對於這樣的東西,可以自然訪問插件,但實際上更多

格子呢是一塊圖案布,通常與蘇格蘭有關,尤其是他們時尚的蘇格蘭語。在Tartanify.com上,我們收集了5,000多個格子呢
