纯CSS解决H5布局中的吸顶吸底的实现步骤
哪些想啥提啥的产品们
最近做了⼀个需求,准确说是迭代需求:加了⼀个头部概览(类似下图),以更好的让⽤户观察到营销变化,故事的开头就这样悄悄的埋下了伏笔。
以前这个页⾯只是⼀个评价列表(可上拉加载),为了数据更易读,列表的头采⽤了固定布局。然⽽加了这个概览时,产品没提,我就简单粗暴的将这个列表头换成了相对布局,ok,提测。
但第⼆天,我发现上拉加载数据多了,列表头部被顶上去之后,想再做筛选,就要再把列表上滑才能看到,这个体验⾮常之差。于是同事就说要不问问产品,要不把概览加概览做成固定。
我第⼀反应就是,恐怕提了之后,产品会让我只把筛选列表头部做成固定,注意那个只。
然后就有了下⾯的对话:
果然怕什么,来什么。但就像同事说的,⾃⼰问的需求,含着泪也要接下。
后⾯经评论提点,⼜加⼊了sticky的⽅案,确实是最优解。
局部吸顶
以下代码是页⾯的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 实现
因为页⾯本⾝就有scroll事件监听,所以第⼀个念头是⽤JS完成,但当时已经下班,⼜是周五,感觉5分钟内搞不定,所以我就跑了。
现在来尝试⽤JS实现,先理⼀下思路:
监听页⾯的滚动,当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');
}
// 取消吸顶
css实现三列布局if (fixed && e.target.scrollTop < titleHeight - 5) {
ve('with-fixed');
fixed = false;
}
});
}, []);
看起也不难,但其实离代码上线,还有很⼤优化的空间,后⾯会分析补充。
CSS Viewport实现
JS 看似很简单,但就像那句热门句⼦:这突如其来的噩耗,让本不富裕的家庭雪上加霜。在这种有下拉加载的页⾯,我们本来就在监听⾥⾯做了很多逻辑处理,所以能⽤CSS实现的,就尽量不要再去⿇烦JS了。
⾸先理⼀下思路,深挖产品的需求:
保持筛选头在可视范围之内(吸顶), 保证可筛选;
当列表数据多时,尽可能多展⽰列表,即概览头部就没必要看到了;
列表是上拉加载的;
当理清上⾯思路时,我们发现,其实就是当列表很长时,隐藏概览头部,简单⽤伪代码表⽰就是(vh是视⼝单位,100vh代表整个屏幕可视⾼度):
if (titleHeight + filterBarHeight + listHeight > 100vh) {
title.hide();
}
那⼜怎样实现概览头部隐藏,⽽筛选头和列表⼜正好出于视⼝呢?
filterBarHeight + listHeight = 100vh
当⽤户往上划,只需要内容(筛选头和列表)正好是⼀个视⼝⾼度(100vh)时,概览头就恰好被隐藏,⽽筛选头⼜正好吸顶,⽤CSS实现就是类似这样的:
// 不是完整代码,详情请看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);
}
最优实现 CSS Sticky
在css中的定位( position )属性值中有个不常⽤的:sticky;
元素根据正常⽂档流进⾏定位,然后相对它的最近滚动祖先和最近块级祖先,包括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时,其采⽤固定定位,就达到吸顶的效果。
对⽐
是不是感觉CSS很简单,稍微设置⼀下即搞定,只是要想到内容⾼度正好是100vh需要⼀点经(yun)验
(qi),经常写H5的,sticky的⽅案相信也是新⼿黏来。其实不光简便,对⽐JS⾄少还有两个个优点:
JS 如果只是上⾯那样,直接将筛选头的定位改成固定定位,眼⼒好的⼈,其实是能感觉到列表有跳变的⼀瞬间,就是列表会突然上移filterBar⾼度,来填补筛选头离开正常⽂档流;(解决⽅案就是在筛选头外多套⼀层dom,并给⼀个固定⾼度,这样筛选头脱离正常⽂档流,但⾼度依旧还在);
当⽤JS来操作Dom元素重排时,这每年⾯试官说的那些重绘重拍我就不多说了,这消耗的性能肯定⾼于CSS实现;
当然,viewport⽅案还有个ios⼿机的兼容性问题,由于safari的头部和底部滑动时可见性会改变,所以当Bar可见时,实际的100vh⾼于屏幕可见⾼度,就会导致吸顶头部被遮挡。到⽬前为⽌,虽然⽹上有很多说height: -webkit-fill-available;,但针对这种场景是⽆效的;但只要依赖100vh,都⾯临这种困局,safari太奇葩,下⼀个IE就是它了.
经过上⾯分析,100vh在IOS safari上的致命问题,会让这种100vh这种纯CSS的⽅案褪⾊。但PC页⾯,或者你和我⼀样,要编写的页⾯是运⾏在APP中(即没有bar存在),那这种⽅案就是可⾏的。所有的⽅案都要具体场景,具体分析,没有谁出⽣就是完美。这⾥只是提⾼⼀种思考⽅式,长点见识。
⽽sticky⽅案不依赖于100vh,其可以⽤100%的写法,所以没有这个担忧,所以相⽐之下,最优解就是sticky ; 但height: 100%是个⽆底洞,你需要从html 标签写起,⼀直写到具有滚动的容器元素。
弹性吸底
说完局部弹性吸顶,再说⼀个常见的,选择性吸底:在页⾯内容不⾜100vh时,我们希望Footer是吸底的,当页⾯内容⼤于100vh时,Footer处于正常⽂档流,让内容可视区域更⼤,⽽⼜不会因为内容太少影响美观,见图:
像第⼀张图那样不做定位的还是⼤有⼈在,因为他们坚信⾃⼰⽹站的内容不会出现不够的时候,但以前更常见做法是底部固定定位。
弹性吸底利⽤min-height加绝对定位,其实现很简单。核⼼代码不超过5⾏css:
body{
position: relative;
min-height: 100vh;
}
footer {
width: 100%;
position: absolute;
bottom: 0;
}
原理就是内容区域最低⾼度为⼀个屏幕,然后底部相对屏幕进⾏绝对定位;当内容变多时,⾼度⼤于100vh,由于是依赖bottom: 0;,所以会⼀直吸底,其巧妙之处就在于此。
针对于这个场景,height: -webkit-fill-available就是有效的。
到此这篇关于纯CSS解决H5布局中的吸顶吸底的实现步骤的⽂章就介绍到这了,更多相关CSS 吸顶吸底内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章,希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论