1、首先简单介绍一下 position: sticky:
position: sticky 是 CSS 定位属性中的一个值,它结合了相对定位(relative)和固定定位(fixed)的特点,允许元素在滚动到特定位置时"粘住"在视口中。
其中和 fixed 属性的本质区别是 sticky 保留了原来的位置,类似 relative 的效果没有跳出文本流,而 fixed 属于跳出原本的文本流,类似于 absolute。
2、那么问题出现了:
问题一:在 ios 环境下,通过JS方法锚点滚动,如果没有加 平滑滚动 behavior:smooth,滚动时会出现闪烁。
问题二:众所周知,在 ios 环境下,元素滑动到最顶部和最底部会出现弹性效果(ios自带的,安卓没有),导致可以一直上划和一直下滑,此时会出现 sticky 的元素异常消失。
3、ios出现问题的原因是什么呢?为什么安卓就不会有问题
主要原因其实就是 iOS 的渲染机制 和 Safari 对 sticky 的特定处理 导致的,其次就是安卓上划下滑到顶部底部没有弹性效果,所以不能一直划动。
4、怎么解决呢?
有说强制让浏览器gpu加速的,有说不按sticky正确使用的,试了都没有效果
然后突然想到,fixed 状态下好像没有这个问题,如果滑动的时候是 fixed,暂停的时候是sticky不就好了。
下面是具体的实现代码:
针对问题一:在点击滚动的时候将sticky元素设置成fixed,然后通过setTimeout还原回sticky
// 解决精选tab切换时,顶部tab导航sticky在ios环境下闪缩问题
const setTopTabFixed = () => {
const stickyEl = document.querySelector('.root-top-tabs');
const rootStickyEl = document.querySelector('.root-page-main');
stickyEl.style.position = 'fixed';
rootStickyEl.style.marginTop = 'var(--header-tab-height)';
setTimeout(() => {
stickyEl.style.position = 'sticky';
rootStickyEl.style.marginTop = '0';
}, 100);
};
```
针对问题二:在上划或者下划的时候监听手指滑动,滑动时将sticky元素设置成fixed(我这里是用上划还原,下划设置fixed,具体情况具体分析)。
```
useEffect(() => {
let startY = 0;
const touchstartFunc = e => {
startY = e.touches[0].clientY;
};
const touchmoveFunc = e => {
const currentY = e.touches[0].clientY;
const isScrollingUp = currentY < startY; // 上划(手指向上移动)
const optTopEle = document.getElementById('optTopEle');
const optListEl = document.getElementById('optListEle');
const stickyEl = document.querySelector('.root-top-tabs');
const rootStickyEl = document.querySelector('.root-page-main');
// console.log(
// '111111111optTopEle.clientHeight',
// optTopEle.clientHeight,
// optTopEle.offsetHeight
// );
// 总高度
const headerHeightValue =
parseFloat(document.documentElement.style.getPropertyValue('--header-tab-height') || '0') +
optTopEle?.clientHeight || 0;
if (isScrollingUp) {
optTopEle.style.position = 'fixed';
stickyEl.style.position = 'fixed';
rootStickyEl.style.marginTop = 'var(--header-tab-height)';
optListEl.style.marginTop = `${headerHeightValue}px`;
} else {
optTopEle.style.position = 'sticky';
stickyEl.style.position = 'sticky';
rootStickyEl.style.marginTop = '0';
optListEl.style.marginTop = '0';
}
};
window.addEventListener('touchstart', touchstartFunc);
window.addEventListener('touchmove', touchmoveFunc);
return () => {
window.removeEventListener('touchstart', touchstartFunc);
window.removeEventListener('touchmove', touchmoveFunc);
};
}, []);
```
总结:
以上就是完美的解决方案了,由于ios 的渲染机制和安卓的不同,导致 sticky 的效果会在滑动等情况下显示异常,这时候通过设置 fixed 过度解决 sticky 闪缩,消失等问题。
做H5端的平时总会遇到一些兼容性问题,只要安卓和ios没有统一,做兼容的工作任重道远啊