[Bug Report] Tabs开启sticky后,在iOS/iPadOS 27上切换tab,触发内核bug,导致页面元素无法响应点击
重现链接
https://github.com/tonliver/vant-tabs-bug
Vant 版本
4.10.2
描述一下你遇到的问题。
在iOS或iPadOS的safari浏览器,使用Tabs组件,开启sticky,滑动至第一个tab页面底部,切换到第二个tab,页面的根节点window/document.documentElememt的scrollTop会变成负值(负值=第一个tab的滚动值),这时页面上所有的布局/鼠标事件坐标都会向下偏移这个scrollTop的绝对值,表现出来就是所有元素都无法响应点击/触摸事件。
关键代码
当有滚动时,rect.top是一个负值
https://github.com/youzan/vant/blob/main/packages/vant/src/utils/dom.ts#L43
// get distance from element top to page top or scroller top
export function getElementTop(el: ScrollElement, scroller?: ScrollElement) {
if (el === window) {
return 0;
}
const scrollTop = scroller ? getScrollTop(scroller) : getRootScrollTop();
return useRect(el).top + scrollTop;
}对root element的scrollTop设置负值
https://github.com/youzan/vant/blob/main/packages/vant/src/tabs/Tabs.tsx#L259
// scroll to correct position
if (stickyFixed && !props.scrollspy) {
setRootScrollTop(
Math.ceil(getElementTop(root.value!) - offsetTopPx.value),
);
}问题分析
在iOS 27之前,无论如何给根节点scrollTop设置负值,浏览器内核最终都会自动处理为0。在iOS 27上,正常情况下也能处理成0,但在页面滚动高度发生变化时,而且必须是滚动到页面底部,个人猜测是触发惯性回弹过程中,负值就会保留下来,随后导致整个布局层坐标偏移(但渲染层正常),虽然是触发了内核的bug,但给根节点传入负的scrollTop也是不应该出现的情况,而且触发bug后,所有元素处于无法交互的状态,影响比较严重,可以在setRootScrollTop内处理一下值的合法性。
UserAgent
User Agent: Mozilla/5.0 (iPad; CPU OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/27.0 Mobile/15E148 Safari/604.1
复现视频
https://github.com/user-attachments/assets/9ca5e257-5d51-4c31-984f-b295d198e393
重现步骤
- 进入页卡1,将页面滑至最底部
- 点击页卡2
设备/浏览器
iOS 27的iphone/ipad上的safari/webview可稳定复现
Source: youzan/vant