一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

CSS如何制作类似探照灯的文字遮罩动画_利用mask-position动态位移

时间:2026-07-17 11:00:54 编辑:袖梨 来源:一聚教程网

mask-position 动画无反应主因是 SVG mask 未设 maskUnits="userSpaceOnUse" 或 PNG 未启用 alpha 通道;推荐用 mask-image 径向渐变+自定义属性动画,配合 mask-size 放大和 mask-repeat:no-repeat 确保光斑覆盖。

mask-position 动画为什么没反应?

直接对 mask-positiontransition@keyframes 却看不到变化,大概率是因为 mask 源是 SVG <mask> 且未设 mask-type: luminance,或用了 PNG 位图但未开启 alpha 通道解析。CSS mask 默认按亮度(luminance)解析遮罩,纯黑/白 PNG 在部分浏览器中会被当全透或全遮,必须显式声明:mask-type: luminance(Chrome 115+ 支持,旧版需用 -webkit-mask + -webkit-mask-type)。

常见错误写法:mask: url(#spotlight) 0 0; —— 这里 0 0 是初始偏移,但若 SVG <mask> 内部 <rect><circle> 没设 width/height 覆盖整个容器,位移就“动在空处”,视觉无变化。

用 CSS mask-image + linear-gradient 做轻量探照灯

不依赖 SVG,用渐变做动态遮罩更可控。核心是:一个高斯模糊的径向渐变作“光斑”,配合 mask-composite: exclude(或反向叠加)挖出文字。

  • mask-image: radial-gradient(circle at var(--x) var(--y), transparent 60%, black 75%) —— --x/--y 控制光心位置,transparent 区域透出文字,black 区域遮住
  • 必须加 mask-size: 300% 300%(或更大),否则光斑太小,位移时很快移出文字范围
  • mask-repeat: no-repeat 防止重复平铺干扰效果
  • 动画只需改 --x--y 自定义属性,再用 transition: --x, --y 0.4s ease-out

示例关键代码:

立即学习“前端免费学习笔记(深入)”;

h1 {  --x: 50%;  --y: 50%;  -webkit-mask: radial-gradient(circle at var(--x) var(--y), transparent 60%, black 75%);  mask: radial-gradient(circle at var(--x) var(--y), transparent 60%, black 75%);  -webkit-mask-size: 300% 300%;  mask-size: 300% 300%;  -webkit-mask-repeat: no-repeat;  mask-repeat: no-repeat;  transition: --x, --y 0.4s ease-out;}h1:hover { --x: 80%; --y: 20%; }

SVG mask 中 mask-position 的实际生效条件

当 mask 源是 SVG 元素(如 url(#spotlight)),mask-position 是否起作用,取决于该 SVG <mask>maskUnits 属性值:

  • maskUnits="userSpaceOnUse":此时 mask-position 的像素值才真正映射到容器坐标系,可动画
  • maskUnits="objectBoundingBox"(默认):mask-position: 100px 100px 会被忽略,因为坐标系是归一化的(0–1)
  • 务必在 SVG <mask> 标签上显式写 maskUnits="userSpaceOnUse",并设 width/height 足够大(如 width="2000"),否则位移超出范围即失效

容易被忽略的一点:CSS 中写的 mask-position: 200px 150px,其参考原点是 mask 图像左上角,不是文字容器——如果 mask 图像本身尺寸小,位移后光斑可能早已脱离文字区域。

鼠标跟随探照灯的坑:position: fixed 导致坐标错乱

想实现鼠标移动时光斑跟随,用 mousemove 更新 --x/--y 很自然,但若文字容器有 transformscroll 或父级 position: fixedclientX/clientY 直接赋值会偏移。

  • 优先用 element.getBoundingClientRect() 获取文字容器视口位置,再计算相对偏移
  • 避免在 body 上监听 mousemove 后直接设全局变量——滚动时 clientY 不变,但文字已上移,光斑悬空
  • 更稳的做法:监听容器上的 mousemove,取 e.offsetX/e.offsetY(注意兼容性,Firefox 不支持 offsetX/Y,需 fallback 到 getBoundingClientRect() 计算)
  • 性能敏感场景记得 throttle,不然高频触发导致 --x/--y 更新卡顿

复杂点在于:mask 渐变中心要对齐鼠标热区,但文字若有 line-heightpaddingtransform: scale(),单纯用 offset 值仍会偏差——这时候得把容器的 getComputedStyle 所有影响布局的属性都纳入偏移修正。

热门栏目