如何为响应式元素打造圆形孔洞以显示下方背景图?
需求:制作带圆形孔洞的响应式牌匾元素
我想把一个元素做成牌匾样式,在四个角落“打孔”,让下方的背景图能透过孔洞显示出来,效果如下:

这个元素是响应式的,可以是竖屏、正方形或横屏形态,但调整形状时,角落的孔洞必须保持圆形,孔洞大小也要响应式,最好和vmin成比例。
初始代码
body { margin: 0; background-image: url(http://picsum.photos/id/167/1000); background-size: cover; height: 100svh; display: flex; justify-content: center; align-items: center; font-family: cursive; font-size: 7vmin; } .d1 { background-color: goldenrod; color: white; width: 60vw; height: 60vh; border-radius: 4vmin; display: flex; justify-content: center; align-items: center; text-align: center; }
<div class="d1">Roses are red,<br>violets are blue.</div>
尝试过的无效方案
我试过用SVG背景图或SVG遮罩,但这两种方案都没法让孔洞保持圆形,代码如下:
body { margin: 0; background-image: url(http://picsum.photos/id/167/1000); background-size: cover; height: 100svh; display: flex; justify-content: center; align-items: center; font-family: cursive; font-size: 7vmin; } .d1 { background-color: goldenrod; color: white; width: 60vw; height: 60vh; border-radius: 4vmin; display: flex; justify-content: center; align-items: center; text-align: center; -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" preserveAspectRatio="none"><circle cx="15" cy="15" r="5"/><circle cx="185" cy="15" r="5"/><circle cx="15" cy="185" r="5"/><circle cx="185" cy="185" r="5"/></svg>') 0/100% 100%, linear-gradient(#fff,#fff); -webkit-mask-composite: destination-out; mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" preserveAspectRatio="none"><circle cx="15" cy="15" r="5"/><circle cx="185" cy="15" r="5"/><circle cx="15" cy="185" r="5"/><circle cx="185" cy="185" r="5"/></svg>') 0/100% 100%, linear-gradient(#fff,#fff); mask-composite: exclude; }
<div class="d1">Roses are red,<br>violets are blue.</div>
解决方案
用CSS径向渐变结合遮罩就能搞定,不用SVG,既能保证孔洞始终是圆形,又能实现响应式。
完整代码
body { margin: 0; background-image: url(http://picsum.photos/id/167/1000); background-size: cover; height: 100svh; display: flex; justify-content: center; align-items: center; font-family: cursive; font-size: 7vmin; } .d1 { background-color: goldenrod; color: white; width: 60vw; height: 60vh; border-radius: 4vmin; display: flex; justify-content: center; align-items: center; text-align: center; /* 统一控制孔洞参数 */ --hole-size: 4vmin; --mask-offset: calc(var(--hole-size) / 2); /* 四个角落的圆形遮罩 */ mask: radial-gradient(circle at var(--mask-offset) var(--mask-offset), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at calc(100% - var(--mask-offset)) var(--mask-offset), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at var(--mask-offset) calc(100% - var(--mask-offset)), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at calc(100% - var(--mask-offset)) calc(100% - var(--mask-offset)), transparent var(--hole-size), black calc(var(--hole-size) + 1px)); /* 兼容webkit内核浏览器 */ -webkit-mask: radial-gradient(circle at var(--mask-offset) var(--mask-offset), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at calc(100% - var(--mask-offset)) var(--mask-offset), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at var(--mask-offset) calc(100% - var(--mask-offset)), transparent var(--hole-size), black calc(var(--hole-size) + 1px)), radial-gradient(circle at calc(100% - var(--mask-offset)) calc(100% - var(--mask-offset)), transparent var(--hole-size), black calc(var(--hole-size) + 1px)); }
<div class="d1">Roses are red,<br>violets are blue.</div>
原理说明
- 用
radial-gradient创建圆形透明区域(即孔洞),黑色区域保留原元素内容,透明区域挖空露出背景。 - 用CSS变量
--hole-size统一控制孔洞大小,vmin单位确保横竖屏切换时,孔洞大小始终和屏幕较小边成比例。 calc(var(--hole-size) / 2)设置孔洞中心距离角落的偏移量,保证孔洞刚好贴合角落,不会错位。- 纯CSS实现,兼容性好,孔洞始终保持圆形,不受元素宽高比例变化影响。
内容的提问来源于stack exchange,提问作者Brett Donald
相关产品推荐
相关产品推荐

