在工作中经常会遇到一个效果就是吸顶,这个菜单一般默认是在某一个未知,然后在滚动的过程中一旦它要从屏幕中消失了就直接吸附在页面的顶部。
当我们看到这个的效果的时候第一反应一般用是js的事件监听scroll,这样的方法必然是兼容效果最好的,但是我们知道这样的方式页面消耗也是很大的,因为每次滚动的时候都要触发,大家一定觉得接下来我要说防抖或者节流,NO,我要说的是position: sticky
position是一个css里面的定位属性,经常会被使用,所以就不多的描述。sticky粘性定位可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。举个栗子:
{position: sticky; top: 100px;}
在 viewport 视口滚动到元素 top 距离小于 100px 之前,元素为相对定位。之后,元素将固定在与顶部距离 10px 的位置,直到 viewport 视口回滚到阈值以下
这个属性似乎可以完美解决我们的需求,but。。。。
image.png
有兼容问题啊~~所以只能用js做一个方法兼容了。判断是否支持这个方法,支持则用该方法实现;不支持就监听scroll
实现如下:
// stickyDom 需要被吸顶的元素
// distance 距离,滚动到哪里的时候开始吸顶【这个如果需要也可以根据吸顶元素做计算,不多做介绍】
// additional 其他希望被写入行内的样式
function positionSticky (stickyDom, distance, additional = {}) {
let styleObj
let checkElement = document.createElement('div')
checkElement.style.position = 'sticky'
document.body.appendChild(checkElement)
let isSupport = /sticky/i.test(window.getComputedStyle(checkElement).position)
document.body.removeChild(checkElement)
if (isSupport) { // 如果支持 position: sticky
styleObj = {
position: 'sticky',
top: 0,
zIndex: 3
}
Object.assign(styleObj, (additional.sticky || {}))
for (let key in styleObj) {
stickyDom.style[key] = styleObj[key]
}
} else { // 如果不支持position: sticky的话直接用滚动监听【这里用到了lodash的debounce】
window.addEventListener('scroll', debounce(function () {
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
if (distance && scrollTop >= distance) {
styleObj = {
position: 'fixed',
zIndex: 3,
top: 0
}
} else {
styleObj = {
position: 'static'
}
}
Object.assign(styleObj, (additional.scroll || {}))
for (let key in styleObj) {
stickyDom.style[key] = styleObj[key]
}
}, 200, { 'maxWait': 1000 }))
}
}
主要功能就完成了。但要备注一下sticky的几个问题:
1、样式表 z-index 无效,行内 style 写有效
2、须指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效
3、父元素固定高度属性会失效
网友评论