body设overflow-hidden结合sr-only元素引发Chrome滚动异常问题
Chrome下含sr-only单选按钮的固定布局滚动异常问题
问题背景
用Svelte+Tailwind开发应用时碰到一个Chrome专属的滚动bug,已用纯HTML/CSS复现:
- 布局逻辑:为实现固定不滚动的header,把
body设为100vw × 100vh并添加overflow:hidden,内部放置固定header和overflow:auto的main区域,原本功能正常。 - 触发场景:给单选按钮加上Tailwind的
sr-only类后,点击视口外的对应label,会触发原本设为不可滚动的body滚动,直接导致布局崩溃。 - 浏览器差异:仅Chrome出现该问题,Firefox完全正常。
- 临时尝试:移除
sr-only类里的position:absolute能解决问题,但担心破坏该类原本的无障碍适配功能。 - 相关线索:曾找到一个已关闭的Chromium相关问题,但未得到有效解决指引。
问题分析
这大概率是Chrome的渲染bug——当点击与position:absolute且超出视口的表单控件绑定的label时,Chrome错误触发了最外层不可滚动容器(此处为body)的滚动行为,而Firefox的事件处理逻辑更符合预期,仅在可滚动的main区域内处理滚动。
解决方案
1. 自定义无position:absolute的sr-only样式
如果不想改动原sr-only类,可以自定义一个视觉隐藏但不影响无障碍的样式替代原类:
.custom-sr-only { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; width: 1px; margin: -1px; overflow: hidden; padding: 0; border: 0; }
该样式同样能让屏幕阅读器识别到控件,同时不会触发Chrome的滚动bug。
2. 拦截label点击的异常滚动
给label添加点击事件,针对Chrome环境阻止默认滚动行为,同时手动切换单选按钮状态:
document.querySelectorAll('label[for]').forEach(label => { if (/Chrome/.test(navigator.userAgent) && !/Edge/.test(navigator.userAgent)) { label.addEventListener('click', e => { const targetInput = document.getElementById(label.getAttribute('for')); if (targetInput && targetInput.classList.contains('sr-only')) { e.preventDefault(); targetInput.checked = !targetInput.checked; } }); } });
这种方式能保留原sr-only类,同时避免触发异常滚动。
3. 调整布局结构规避bug
把overflow:hidden从body移到内部容器,比如用一个#app容器包裹header和main,设置#app为100vw × 100vh且overflow:hidden,body恢复默认样式。从布局层面避开Chrome的bug触发条件,是比较稳妥的方案。
内容的提问来源于stack exchange,提问作者Erwan Leroy
相关产品推荐
相关产品推荐

