純CSS解決H5布局中的吸頂吸底的實現(xiàn)步驟

哪些想啥提啥的產(chǎn)品們
最近做了一個需求,準確說是迭代需求:加了一個頭部概覽(類似下圖),以更好的讓用戶觀察到營銷變化,故事的開頭就這樣悄悄的埋下了伏筆。
以前這個頁面只是一個評價列表(可上拉加載),為了數(shù)據(jù)更易讀,列表的頭采用了固定布局。然而加了這個概覽時,產(chǎn)品沒提,我就簡單粗暴的將這個列表頭換成了相對布局,ok,提測。
但第二天,我發(fā)現(xiàn)上拉加載數(shù)據(jù)多了,列表頭部被頂上去之后,想再做篩選,就要再把列表上滑才能看到,這個體驗非常之差。于是同事就說要不問問產(chǎn)品,要不把概覽加概覽做成固定。
我第一反應就是,恐怕提了之后,產(chǎn)品會讓我 只
把篩選列表頭部做成固定,注意那個只。
然后就有了下面的對話:
果然怕什么,來什么。但就像同事說的,自己問的需求,含著淚也要接下。
后面經(jīng)評論提點,又加入了sticky的方案,確實是最優(yōu)解。
局部吸頂
以下代碼是頁面的 dom
結構
<div id="demo" className={style.demo}> <h3 id="title" className="title">這是一個概覽頭部</h3> <div id="content" className="content"> <div className="filter-bar"> <h3>這是列表頭部</h3> <h3>可篩選</h3> <h3>下面是滾動列表</h3> </div> <ul className="list"> {arr.map(({ key, label }) => <li key={key}>{label}</li>)} </ul> </div> </div>
JS 實現(xiàn)
因為頁面本身就有scroll事件監(jiān)聽,所以第一個念頭是用JS完成,但當時已經(jīng)下班,又是周五,感覺5分鐘內搞不定,所以我就跑了。
現(xiàn)在來嘗試用JS實現(xiàn),先理一下思路:
- 監(jiān)聽頁面的滾動,當ul元素頂部距離頁面頂部大于title 高度時,添加一個css類使篩選頭部吸頂;
- 當ul元素距離頂部小于等于title 高度時,刪除添加的類,取消篩選頭部吸頂
JS 代碼
useEffect(() => { const demo = document.querySelector('#demo'); const content = document.querySelector('#content'); const titleHeight = document.querySelector('#title').clientHeight; let fixed = false; demo.addEventListener('scroll', (e) => { // 添加吸頂 if (!fixed && e.target.scrollTop >= titleHeight) { fixed = true; content.classList.add('with-fixed'); } // 取消吸頂 if (fixed && e.target.scrollTop < titleHeight - 5) { content.classList.remove('with-fixed'); fixed = false; } }); }, []);
看起也不難,但其實離代碼上線,還有很大優(yōu)化的空間,后面會分析補充。
CSS Viewport實現(xiàn)
JS 看似很簡單,但就像那句熱門句子: 這突如其來的噩耗,讓本不富裕的家庭雪上加霜
。在這種有下拉加載的頁面,我們本來就在監(jiān)聽里面做了很多邏輯處理,所以能用CSS實現(xiàn)的,就盡量不要再去麻煩JS了。
首先理一下思路,深挖產(chǎn)品的需求:
- 保持篩選頭在可視范圍之內(吸頂), 保證可篩選;
- 當列表數(shù)據(jù)多時,盡可能多展示列表,即概覽頭部就沒必要看到了;
- 列表是上拉加載的;
當理清上面思路時,我們發(fā)現(xiàn),其實就是當列表很長時,隱藏概覽頭部,簡單用偽代碼表示就是(vh是視口單位 ,100vh代表整個屏幕可視高度):
if (titleHeight + filterBarHeight + listHeight > 100vh) { title.hide(); }
那又怎樣實現(xiàn)概覽頭部隱藏,而篩選頭和列表又正好出于視口呢?
filterBarHeight + listHeight = 100vh
當用戶往上劃,只需要內容(篩選頭和列表)正好是一個視口高度(100vh)時,概覽頭就恰好被隱藏,而篩選頭又正好吸頂,用CSS實現(xiàn)就是類似這樣的:
// 不是完整代碼,詳情請看demo: .demo { :global { .title { height: 15vh; line-height: 15vh; text-align: center; border-bottom: 1PX solid #eee; background-color: #fff; } .filter-bar { height: 15vw; background-color: #888; display: flex; align-items: center; } .list { max-height: calc(100vh - 15vw);; // 這里的設置很重要 overflow: scroll; background-color: rgba(127, 255, 212, .8); }
最優(yōu)實現(xiàn) CSS Sticky
在css中的定位( position
)屬性值中有個不常用的: sticky
;
元素根據(jù)正常文檔流進行定位,然后相對它的最近滾動祖先和最近塊級祖先,包括table-related元素,基于top, right, bottom, 和 left的值進行偏移。粘性定位可以被認為是相對定位和固定定位的混合。元素在跨越特定閾值前為相對定位,之后為固定定位。
這里我們在沿用JS的方案上進行更改,只需要將filter-bar 的定位屬性改為粘性定位,就可以去除對 JS 的依賴;
.demo { max-height: 100%; overflow: scroll; .filter-bar { position: sticky; top: 0; } }
demo類作用于最外層dom( <div className={style.demo}>
)上,其視高為100vh,當內容超出高度時為滾動;filter-bar 元素采用粘性定位,當高度距離demo元素大于0時,其采用相對定位,即以正常文檔流的形式定位;當高度小于等于0時,其采用固定定位,就達到吸頂?shù)男Ч?/p>
對比
是不是感覺CSS很簡單,稍微設置一下即搞定,只是要想到內容高度正好是 100vh
需要一點經(jīng)(yun)驗(qi),經(jīng)常寫H5的,sticky的方案相信也是新手黏來。其實不光簡便,對比JS至少還有兩個個優(yōu)點:
- JS 如果只是上面那樣,直接將篩選頭的定位改成固定定位,眼力好的人,其實是能感覺到列表有跳變的一瞬間,就是列表會突然上移filterBar高度,來填補篩選頭離開正常文檔流;(解決方案就是在篩選頭外多套一層dom,并給一個固定高度,這樣篩選頭脫離正常文檔流,但高度依舊還在);
- 當用JS來操作Dom元素重排時,這每年面試官說的那些重繪重拍我就不多說了,這消耗的性能肯定高于CSS實現(xiàn);
當然,viewport方案還有個ios手機的兼容性問題,由于safari的頭部和底部滑動時可見性會改變,所以當Bar可見時,實際的100vh高于屏幕可見高度,就會導致吸頂頭部被遮擋。到目前為止,雖然網(wǎng)上有很多說 height: -webkit-fill-available;
,但針對這種場景是無效的;但只要依賴100vh,都面臨這種困局,safari太奇葩,下一個IE就是它了.
經(jīng)過上面分析,100vh在IOS safari上的致命問題,會讓這種100vh這種純CSS的方案褪色。但PC頁面,或者你和我一樣,要編寫的頁面是運行在APP中(即沒有bar存在),那這種方案就是可行的。所有的方案都要具體場景,具體分析,沒有誰出生就是完美。這里只是提高一種思考方式,長點見識。
而sticky方案不依賴于100vh,其可以用100%的寫法,所以沒有這個擔憂,所以相比之下,最優(yōu)解就是 sticky
; 但 height: 100%
是個無底洞,你需要從html 標簽寫起,一直寫到具有滾動的容器元素。
彈性吸底
說完局部彈性吸頂,再說一個常見的,選擇性吸底:在頁面內容不足100vh時,我們希望 Footer
是吸底的,當頁面內容大于100vh時, Footer
處于正常文檔流,讓內容可視區(qū)域更大,而又不會因為內容太少影響美觀,見圖:
像第一張圖那樣不做定位的還是大有人在,因為他們堅信自己網(wǎng)站的內容不會出現(xiàn)不夠的時候,但以前更常見做法是底部固定定位。
彈性吸底利用 min-height
加絕對定位,其實現(xiàn)很簡單。核心代碼不超過5行css:
body{ position: relative; min-height: 100vh; } footer { width: 100%; position: absolute; bottom: 0; }
原理就是內容區(qū)域最低高度為一個屏幕,然后底部相對屏幕進行絕對定位;當內容變多時,高度大于100vh,由于是依賴 bottom: 0;
,所以會一直吸底,其巧妙之處就在于此。
針對于這個場景, height: -webkit-fill-available
就是有效的。
到此這篇關于純CSS解決H5布局中的吸頂吸底的實現(xiàn)步驟的文章就介紹到這了,更多相關CSS 吸頂吸底內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持腳本之家!
相關文章
- 這篇文章主要介紹了Html5導航欄吸頂方案原理與對比實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起2020-06-10
css實現(xiàn)5種滾動吸頂實現(xiàn)方式的比較(性能升級版)
這篇文章主要介紹了css實現(xiàn)5種滾動吸頂實現(xiàn)方式的比較(性能升級版),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著2019-07-31- 吸頂是一種比較常見的交互效果,當頁面滑出屏幕邊界,標題會自動吸附在屏幕邊緣,用于提示用戶,這篇文章主要介紹了Html5之title吸頂功能的相關資料,感興趣的小伙伴們可以2018-06-04