原生video或canvas穿透遮罩层的根本原因是其运行在浏览器ui层或合成层,高于css渲染层;解法包括移除controls、自建控件、显式设置position与z-index、避免意外创建层叠上下文。

原生 <video></video> 或 <canvas></canvas> 元素会穿透 CSS 遮罩层,不是 z-index 没设高,而是它们运行在浏览器 UI 层或合成层,天然高于普通 DOM 渲染层。
video controls 穿透遮罩层的典型表现
即使遮罩层 z-index: 9999、position: fixed,点击进度条、全屏按钮仍能触发;部分安卓 WebView 或旧版 Safari 中,遮罩甚至完全不可见。
- 根本原因是
controls属性启用的原生控件运行在浏览器 UI 层,不参与 CSS 层叠上下文计算 -
transform: translateZ(0)或will-change: transform强制提升图层效果不稳定,iOS Safari 15.4 前基本无效 - 不能只靠提高遮罩 z-index——必须让遮罩和
<video></video>处于同一渲染层级,或彻底移除原生控件
canvas 元素“吃掉”遮罩层的真实原因
<canvas></canvas> 默认不响应 z-index 的常规堆叠顺序,它的实际层级取决于是否被其他元素的 transform、filter 或 opacity 拉入更高合成层。
- 错误做法:把
<canvas></canvas>放在position: relative容器里,再给兄弟元素设z-index: 10——Canvas 往往仍压在上面 - 可靠解法:给
<canvas></canvas>和遮罩层都显式设置position: absolute或fixed,并统一指定z-index(如 Canvas 设为1,遮罩设为100) - 若 Canvas 用于实时绘制,避免用
transform: scale()控制尺寸——应改用 JS 动态重设canvas.width/canvas.height并调用ctx.scale()
遮罩层与原生组件的 DOM 位置关系必须严格对齐
遮罩层必须与 <video></video> 或 <canvas></canvas> 同级,或直接包裹它;任何中间父容器若带有 transform、filter、opacity ,都会意外创建层叠上下文,导致 z-index 失效。
- 不要把遮罩层挂到
body下而让<video></video>留在局部组件内——DOM 层级错位会让浏览器无法正确比较渲染顺序 - 推荐结构:
<div class="media-wrapper"> <video src="..."></video><div class="overlay"></div> </div>
然后对.media-wrapper设position: relative,.overlay设position: absolute; z-index: 100 - 如果必须用
teleport(如 Vue 中),确保<video></video>也被同步移出,否则仍存在层级断层
最易被忽略的是:视频控件穿透问题在 PC 模拟器上几乎不复现,但真机必现;Canvas 层级异常往往只在开启硬件加速的设备上暴露。务必在 iOS Safari、微信内置浏览器、主流安卓 WebView 上逐个验证 DOM 结构和渲染层状态。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











