如何在Overlay上制作镂空区域以显示下层视频内容?
实现带镂空区域的全屏视频遮罩
需求:全屏黑色遮罩覆盖屏幕,遮罩上显示白色文字,在.video-gap所在位置将遮罩镂空,露出下方视频。询问仅用CSS或CSS+JS的实现方案。

原始代码示例
HTML
<div class="video-container"> <video autoplay muted playsinline loop > <source src="./video/video.mp4" /> </video> <div class="video-overlay"> <div class="text-container"> <h1 class="text-line">We're here <div class="video-gap"></div> to make</h1> <h1 class="text-line">healthy <div class="video-gap"></div> living effortless,</h1> <h1 class="text-line">so you can <div class="video-gap"></div> live longer</h1> <h1 class="text-line">and happier <div class="video-gap"></div> </h1> </div> </div> </div>
CSS
.video-container { height: 100vh; width: 100%; } .video-container video { display: block; width: 100%; height: 100%; object-fit: cover; } .video-overlay { position: absolute; z-index: 2; top: 0; left: 0; right: 0; bottom: 0; display: flex; place-items: center; place-content: center; background-color: rgb(4, 4, 4); z-index: 1; } .text-container { width: 100%; height: 100%; z-index: 2; } .text-line { width: 100%; max-height: 120px; display: flex; justify-content: space-between; gap: 20px; color: white; font-size: 100px; } .video-gap { position: relative; width: max-content; background-color: transparent; flex-grow: 1; border: 1px solid red; }
推荐实现方案:CSS+JS(适配动态场景)
该方案通过JS动态计算.video-gap的位置,配合CSS的mask属性实现精准镂空,兼容所有现代浏览器,支持窗口缩放、文字换行等动态场景。
修改后的完整代码
HTML(无需改动)
同原始HTML代码
CSS
.video-container { height: 100vh; width: 100%; position: relative; /* 让内部绝对定位元素基于此容器 */ overflow: hidden; } .video-container video { display: block; width: 100%; height: 100%; object-fit: cover; } .video-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgb(4, 4, 4); /* 初始遮罩为全显示,后续JS动态修改 */ mask: rect(0 100% 100% 0); -webkit-mask: rect(0 100% 100% 0); } .text-container { width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; padding: 0 2rem; position: relative; z-index: 1; /* 确保白色文字在遮罩上方可见 */ } .text-line { width: 100%; max-height: 120px; display: flex; justify-content: space-between; align-items: center; gap: 20px; color: white; font-size: clamp(2rem, 8vw, 6.25rem); /* 响应式字体,适配不同屏幕 */ margin: 0.5rem 0; } .video-gap { flex-grow: 1; height: 100%; /* 仅用于占位,移除原始红色边框 */ }
JS
function updateOverlayMask() { const overlay = document.querySelector('.video-overlay'); const gaps = document.querySelectorAll('.video-gap'); const maskRects = []; gaps.forEach(gap => { const rect = gap.getBoundingClientRect(); const overlayRect = overlay.getBoundingClientRect(); // 计算镂空区域相对于遮罩层的坐标 const x = rect.left - overlayRect.left; const y = rect.top - overlayRect.top; const width = rect.width; const height = rect.height; // 生成mask所需的rect参数格式:y1 x2 y2 x1 maskRects.push(`rect(${y}px ${x + width}px ${y + height}px ${x}px)`); }); if (maskRects.length) { // 设置遮罩:保留全屏区域,排除所有镂空区域 overlay.style.mask = `rect(0 100% 100% 0), ${maskRects.join(', ')}`; overlay.style.maskComposite = 'exclude'; // 兼容webkit内核浏览器(如Chrome、Safari) overlay.style.webkitMask = `rect(0 100% 100% 0), ${maskRects.join(', ')}`; overlay.style.webkitMaskComposite = 'xor'; } } // 页面加载和窗口缩放时更新遮罩 window.addEventListener('load', updateOverlayMask); window.addEventListener('resize', updateOverlayMask);
核心原理
- 遮罩层基础:
.video-overlay作为全屏黑色遮罩,初始mask设置为全显示状态。 - 文字层级:
.text-container设置z-index:1,确保白色文字始终在遮罩上方,不会被遮罩影响。 - 动态计算:JS通过
getBoundingClientRect()获取每个.video-gap的位置和尺寸,转换为遮罩层的相对坐标。 - 遮罩生成:将多个镂空区域的
rect参数组合到mask属性中,通过mask-composite: exclude排除这些区域,露出下方视频。
纯CSS替代方案(仅适用于固定布局)
如果.video-gap的位置和尺寸是固定不变的,可以直接在CSS中写死mask参数,无需JS:
.video-overlay { /* 示例:4个固定位置的镂空区域,根据实际需求修改坐标 */ mask: rect(0 100% 100% 0), rect(100px 600px 220px 300px), rect(250px 700px 370px 400px), rect(400px 650px 520px 350px), rect(550px 600px 670px 300px); mask-composite: exclude; -webkit-mask: rect(0 100% 100% 0), rect(100px 600px 220px 300px), rect(250px 700px 370px 400px), rect(400px 650px 520px 350px), rect(550px 600px 670px 300px); -webkit-mask-composite: xor; }
注意:该方案灵活性差,无法适配窗口缩放、文字换行等动态场景,仅适合静态固定布局。
内容的提问来源于stack exchange,提问作者Vladimiro Antipin
相关产品推荐
相关产品推荐

