直接用 width 控制图层会卡顿甚至白屏,因频繁修改 width 触发 layout 重排,尤其在中低端安卓机或 safari 上;应改用 transform + overflow:hidden 方案,避免 layout 触发点。

为什么直接用 width 控制图层会卡顿甚至白屏
很多人一上来就给两张 <img> 分别加 width 样式,拖动滑块时动态改 style.width,结果在中低端安卓机或 Safari 上明显掉帧,松手后还跳变。这不是 JS 性能差,而是每次改 width 都触发浏览器 layout(重排),而拖动时 input 事件每秒可能触发 60+ 次。
- 绝对定位图层的
width: 65%计算依赖父容器当前 layout 尺寸;图片加载、窗口 resize 后,getBoundingClientRect().width可能还没稳定,导致初始裁剪错位 - 移动端 touchmove 触发更密集,没节流就等于主动压垮渲染线程
- 用
calc(65% - 1px)这类混合单位写法,resize 后像素值不会自适应,分界线立刻偏移
用 transform + overflow:hidden 替代 width 的实操要点
真正轻量稳定的方案是:左侧图层缩放,右侧图层平移,共用一个 ratio(0–1),全程避开 width 和 left 的 layout 触发点。
- 父容器必须设
position: relative且宽高明确(不能靠内容撑开),否则子元素定位基准漂移 - 左侧图层(基准图):
transform: scaleX(ratio)+transform-origin: left - 右侧图层(对比图):
left: calc(-100% + (100% * ratio))或transform: translateX(calc(-100% + (100% * ratio))) - 父容器加
overflow: hidden,否则右侧图层平移后会溢出 - JS 中缓存一次
container.offsetWidth,后续所有计算都基于它,不反复读getBoundingClientRect()
监听 input 事件而非 change 是硬性要求
<input type="range"> 的 change 事件只在松手后触发一次,无法实现拖拽过程中的实时对比。必须用 input 事件,但要注意兼容性和性能。
- 移动端需给 range 元素加
touch-action: none,否则 iOS Safari 会截断事件流 - 拖动过程中必须调用
e.preventDefault(),否则页面可能意外滚动 - 更新样式前套一层
requestAnimationFrame节流,避免连续 layout - 用
event.target.valueAsNumber / 100直接转成ratio,比parseInt(value)更安全(支持小数输入)
图片加载完成前千万别初始化滑块逻辑
常见错误是 DOM 加载完就立即绑定事件、读 img.width,但此时图片还没加载,img.naturalWidth 为 0,导致 clip-path 或 transform 初始值错乱,拖动第一下就跳变。
- 必须等两张图都触发
onload后再初始化——可封装为Promise.all([img1.onload, img2.onload]) - 给
<img>加loading="eager",防止懒加载干扰时序 - 加载失败时设
input.disabled = true并显示 fallback 提示 - 若图源来自 CMS,建议用
img.naturalWidth而非 CSS 渲染后的offsetWidth,避免因object-fit缩放导致宽高误判
最常被忽略的一点:所有 transform、left、clip-path 值必须统一用百分比或 calc(),不能一半写 50%、一半写 200px——resize 后像素值不会自适应,分界线立刻偏移。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











