全屏轮播需解决视口计算、图片拉伸、滚动穿透、键盘焦点丢失四问题:用JS动态更新--vh变量替代100vh;多尺寸图+srcset优先应对拉伸;touch-action: pan-y配合精准preventDefault防滚动穿透;轮播项设tabindex、aria-current等保障可访问性。

全屏轮播不是加个 height: 100vh 就完事的——真正卡住你的,是视口计算、图片拉伸、滚动穿透、键盘焦点丢失这四点。
为什么 height: 100vh 在手机上会失效
移动端 Safari 和部分安卓浏览器在地址栏收放时会动态改变 vh 值,导致轮播容器突然缩高或溢出。iOS 上甚至可能触发两次 resize,造成图片错位。
更稳妥的做法是用 JS 动态读取 window.innerHeight 并写入内联样式:
function updateVh() {
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`);
}
window.addEventListener('resize', updateVh);
updateVh(); // 初始化
然后 CSS 中用 height: calc(var(--vh, 1vh) * 100) 替代 100vh。注意:必须绑定到 document.documentElement,否则 iOS 下可能拿不到最新高度。
立即学习“前端免费学习笔记(深入)”;
background-size: cover 拉伸变形的三种应对方式
全屏 banner 最常被吐槽“人脸被压扁”“文字被裁掉”,本质是图片宽高比和屏幕不匹配。不能只靠 CSS。
- 服务端提前生成多套尺寸图(如
banner-1920x1080.jpg、banner-375x812.jpg),用<picture>+srcset切换 - 前端 JS 检测当前视口宽高比,动态加载对应比例图:
fetch(`/api/banner?ratio=${w/h}`) - 纯 CSS 方案:给
<img>加object-fit: cover+object-position: center top(慎用,Safari 旧版不支持)
优先选第一种——CDN 缓存友好,首屏不闪,且能规避 JS 加载失败时的空白问题。
轮播组件如何避免滚动穿透(iOS 最典型)
手指在轮播图上左右滑动时,如果松手位置偏上或偏下,页面会跟着上下滚动,这是 iOS 默认行为。关键不是禁用 touchmove,而是精准拦截:
- 监听
touchstart记录起始 X 坐标 - 在
touchmove中判断Math.abs(currentX - startX) > Math.abs(currentY - startY),只在横向滑动时preventDefault() - 必须给轮播容器加
touch-action: pan-y(禁用纵向拖拽),否则 Chrome 会忽略preventDefault
漏掉 touch-action 是最常见错误——光写 JS 阻止事件,iOS 仍会响应原生滚动。
键盘用户无法用 Tab 切换轮播项?那是没管好 tabindex
全屏轮播常被当成视觉组件忽略可访问性。实际要满足三点:
- 每个轮播项的容器设
tabindex="0",确保能被聚焦 - 当前激活项加
aria-current="true",隐藏项加aria-hidden="true" - 左右箭头按钮必须有
aria-label="上一张" / "下一张",且disabled状态要同步更新aria-disabled
别依赖 focusable 属性——它只在 SVG 里有效,HTML 元素必须显式写 tabindex。
轮播最难的从来不是切换动画,而是让不同设备、不同输入方式、不同网络条件下都保持一致的尺寸和交互反馈。尤其 --vh 变量和 touch-action 这两个点,线上 bug 出现率最高,但文档里往往一笔带过。



















