1. 圆形透明滤镜到底解决什么问题
网页里的圆形透明滤镜,说白了就是让某个区域“挖个洞”,洞里的内容正常显示,洞外被遮罩或模糊。最常见的落地场景有三类:头像镂空(圆形头像框外圈压暗)、卡片聚焦(鼠标移到卡片上,周围变暗突出当前卡片)、引导蒙层(新手引导时高亮某个按钮)。这类效果如果只用border-radius加overflow: hidden,只能裁切元素本身,没法处理“洞外”的遮罩,所以真正干活的是mask和backdrop-filter这两个属性。
mask负责定义“哪里可见、哪里透明”,它接受一张遮罩图或渐变,遮罩里透明的地方元素就透明,不透明的地方元素就显示。backdrop-filter则是把元素背后的内容做模糊、亮度、饱和度等处理,配合圆形遮罩就能做出“圆形区域内清晰、区域外模糊”的毛玻璃效果。两者组合,圆形透明滤镜的两种主流形态就出来了:一种是纯遮罩挖洞,一种是遮罩加背景模糊。
这篇面向的是想在项目里快速复用这套效果的开发者,不管你是做个人主页、后台管理系统的引导层,还是电商卡片的聚焦交互,都能直接抄配置。下面我会先讲清楚 TaoToken 在这个流程里能帮上什么忙(尤其是调试和验证阶段),再给可复制的 CSS 片段,然后是浏览器兼容性验证步骤,最后把常见的坑一个个列出来。
2. TaoToken 在调试与验证环节的前置准备
写 CSS 效果本身不需要联网,但你在验证阶段大概率会遇到两个问题:一是想快速对比不同参数下的渲染结果,二是想确认某些属性在目标浏览器里的实际表现。这时候如果手边有一个能直接对话、能贴代码问问题的模型入口,会省很多来回搜索的时间。TaoToken 的模型对话入口(https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)就是干这个的,你可以把mask的渐变参数贴进去,让它帮你解释每个色标的作用,或者把报错信息丢进去问原因。
如果你是要把这类效果接进一个长期维护的前端项目,甚至后面想用 Agent 辅助写样式,那 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)会更合适,它面向的是持续性的编码任务,不是单次问答。接入方式上,API 地址是 https://taotoken.net/api,Key 在控制台(https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)里生成,具体怎么配可以看接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)。这里要说明一点:TaoToken 是正常的模型调用服务,不是用来替代你本地编辑器的,CSS 还是在你自己的项目里写,它只是帮你查资料、解释属性、验证思路。
前置准备其实就三件事:一个能跑 HTML 的本地环境(直接建个.html文件用浏览器打开就行)、一个目标浏览器(Chrome 或 Edge 都行,后面兼容性会讲 Safari 的差异)、以及一个能贴代码问问题的入口。不需要装任何构建工具,纯静态页面就能验证。
3. 可复制的 CSS mask 与 backdrop-filter 配置
先给最核心的圆形遮罩挖洞写法。原理是用radial-gradient做遮罩图,圆心透明、外圈不透明,这样元素中间就“挖”出一个圆。
/* 圆形挖洞遮罩:中间透明,四周不透明 */ .circle-mask { position: absolute; inset: 0; /* 遮罩图:圆心 160px 内透明,200px 外完全不透明 */ -webkit-mask-image: radial-gradient( circle at 50% 50%, transparent 160px, #000 200px ); mask-image: radial-gradient( circle at 50% 50%, transparent 160px, #000 200px ); /* 遮罩层本身的背景色,决定洞外压暗的程度 */ background: rgba(0, 0, 0, 0.85); pointer-events: none; }这里有几个参数要理解清楚。circle at 50% 50%是圆心位置,改成at 30% 40%就能把洞挪到别处。transparent 160px表示从圆心到 160px 半径范围内完全透明,#000 200px表示 200px 半径外完全不透明,中间 160 到 200px 是渐变过渡带,过渡带越窄边缘越硬,越宽边缘越柔和。-webkit-mask-image是给 Safari 和旧版 WebKit 内核用的,标准写法mask-image也要写上,两个都写才稳。
如果你要的是“圆形区域内清晰、区域外模糊”的毛玻璃效果,那就把遮罩和backdrop-filter结合:
/* 圆形毛玻璃:洞内清晰,洞外模糊 */ .circle-blur { position: absolute; inset: 0; backdrop-filter: blur(8px) brightness(0.7); -webkit-backdrop-filter: blur(8px) brightness(0.7); -webkit-mask-image: radial-gradient( circle at 50% 50%, transparent 140px, #000 180px ); mask-image: radial-gradient( circle at 50% 50%, transparent 140px, #000 180px ); pointer-events: none; }注意backdrop-filter必须配合-webkit-backdrop-filter才能在 Safari 里生效,而且它处理的是元素背后的内容,所以这个元素本身要盖在图片或卡片上方。brightness(0.7)是顺带把洞外压暗一点,不加也行,看你要的效果。
再给一个跟随鼠标移动的版本,把圆心位置用 JS 动态算出来:
const mask = document.querySelector('.circle-mask'); window.addEventListener('mousemove', (e) => { const x = (e.clientX / window.innerWidth) * 100; const y = (e.clientY / window.innerHeight) * 100; mask.style.maskImage = `radial-gradient(circle at ${x}% ${y}%, transparent 160px, #000 200px)`; mask.style.webkitMaskImage = `radial-gradient(circle at ${x}% ${y}%, transparent 160px, #000 200px)`; });这里用clientX/clientY配合innerWidth/innerHeight算百分比,比pageX/pageY更稳,因为页面滚动时pageX会带上滚动偏移,圆心会跑偏。如果你确实需要处理滚动场景,记得把scrollX/scrollY减掉。
4. 验证请求与成功结果确认
配置写完之后,怎么确认它真的生效了?分三步走。
第一步,建一个最小 HTML 文件,把下面这段贴进去,用浏览器打开:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <style> body { margin: 0; height: 100vh; background: url('https://images.unsplash.com/photo-1519677100203-a0e668c92439') no-repeat center / cover; } .circle-mask { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.85); -webkit-mask-image: radial-gradient(circle at 50% 50%, transparent 160px, #000 200px); mask-image: radial-gradient(circle at 50% 50%, transparent 160px, #000 200px); pointer-events: none; } </style> </head> <body> <div class="circle-mask"></div> </body> </html>打开后你应该看到:页面中间有一个圆形区域是清晰的背景图,圆形外被一层半透明黑色压暗。如果整个页面全黑或者全亮,说明遮罩没生效,去排查章节找原因。
第二步,打开开发者工具(F12),选中.circle-mask元素,在 Styles 面板里看mask-image有没有被划掉。如果被划掉,说明浏览器不认这个写法,检查是不是漏了-webkit-前缀。在 Computed 面板里搜mask,能看到最终计算值,确认渐变参数和你写的一致。
第三步,验证backdrop-filter版本。把.circle-mask换成.circle-blur的样式,刷新后圆形区域内应该是清晰的,区域外是模糊加变暗的。如果模糊没出来,先确认元素背后确实有内容(背景图或卡片),backdrop-filter对纯色背景是看不出效果的。
成功的结果就是:圆形边界清晰、过渡带自然、鼠标移动时圆心跟随流畅不卡顿。如果边界有锯齿,把过渡带拉宽一点,比如从160px/200px改成140px/220px。
5. 本篇常见错误排查
遮罩完全不生效,页面全黑或全亮。最常见的原因是只写了mask-image没写-webkit-mask-image,或者反过来。Safari 和部分旧版 Chrome 只认-webkit-前缀,两个都写最保险。另一个原因是遮罩元素没有尺寸,position: absolute配inset: 0是让它铺满父容器,如果父容器没有定位上下文,它可能撑不开,给父容器加position: relative。
圆形边缘有锯齿或过渡生硬。radial-gradient的过渡带太窄会导致边缘硬,把两个色标的距离拉大,比如transparent 140px, #000 220px,80px 的过渡带会柔和很多。如果还是有锯齿,检查是不是用了px但页面缩放了,改用vmin或百分比能让它在不同屏幕下更均匀。
backdrop-filter 没效果。三个检查点:元素背后有没有实际内容、有没有写-webkit-backdrop-filter、父元素有没有overflow: hidden把它裁掉了。另外backdrop-filter在某些嵌套的transform容器里会失效,如果父级有transform: translateZ(0)之类的,试着去掉。
鼠标跟随时光圈跳动或延迟。用mousemove直接改style.maskImage会触发重绘,如果页面元素多会卡。可以加requestAnimationFrame节流:
let rafId = null; window.addEventListener('mousemove', (e) => { if (rafId) return; rafId = requestAnimationFrame(() => { const x = (e.clientX / window.innerWidth) * 100; const y = (e.clientY / window.innerHeight) * 100; mask.style.maskImage = `radial-gradient(circle at ${x}% ${y}%, transparent 160px, #000 200px)`; mask.style.webkitMaskImage = `radial-gradient(circle at ${x}% ${y}%, transparent 160px, #000 200px)`; rafId = null; }); });Safari 里圆心位置偏移。Safari 对mask-image里百分比圆心的解析和 Chrome 有细微差异,尤其是配合background-attachment: fixed时。稳妥做法是用px算绝对位置,或者把遮罩层放在一个和背景图同尺寸的容器里,圆心用容器内的百分比。
移动端触摸没有跟随。mousemove在移动端不触发,要加touchmove监听,并且记得e.preventDefault()防止页面滚动,同时用e.touches[0].clientX取坐标。
6. 按场景选择入口继续深入
如果你只是想把这篇的 CSS 片段跑通、遇到报错想快速问清楚,直接用模型对话入口(https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)贴代码问就行,不用配 Key。如果你要把这套效果接进一个持续迭代的前端项目,后面还想让 Agent 帮你批量改样式、写兼容代码,那先去控制台(https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)生成 API Key,再照着接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)把环境配好,长期编码任务用 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)更顺手。API 地址统一是 https://taotoken.net/api,官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。
最后补一个我实际踩过的坑:mask-image的渐变里,transparent在部分浏览器里会被解析成rgba(0,0,0,0),如果遮罩层本身有颜色,过渡带可能出现灰边。稳妥写法是用rgba(0,0,0,0)显式声明透明,别偷懒写transparent。这个细节在 Chrome 里看不出来,Safari 里一眼就能看到灰圈。