hover时遮罩层从中心扩散需设transform-origin: center并配合scale(0)→scale(1),否则默认左上角缩放;须绝对定位、避免width/height动画、同步border-radius、慎用transition-delay。

hover 触发时遮罩层从中心扩散,关键在 transform-origin + scale
直接用 :hover 配合 scale(0) → scale(1) 不会从中心扩散——默认以元素左上角为原点缩放。必须显式设置 transform-origin: center,否则动画看起来是“偏的”或“拉伸的”。
常见错误:只写 transition: transform 0.3s 却没设 transform-origin,结果遮罩层从左上角炸开;或者用了 width/height 动画,导致重排(layout thrashing),卡顿明显。
- 遮罩层需绝对定位、覆盖父容器,且初始
opacity: 0+transform: scale(0) - 父容器要设
position: relative,否则absolute遮罩层可能错位 - 过渡属性只写
transform和opacity,避免触发布局计算 - 若父容器有圆角(
border-radius),遮罩层也要同步加相同值,否则扩散时边缘露白
兼容性与性能:别用 transition-delay 模拟“延迟扩散”
有人想让遮罩先等 0.1s 再动,就加 transition-delay。这会导致鼠标移入瞬间无响应,体验割裂。更自然的做法是用 cubic-bezier(0.34, 1.56, 0.64, 1) 这类弹性缓动,让 scale 从慢→快→微回弹,视觉上像“弹出”而非机械展开。
IE11 不支持 transform-origin: center 在伪元素上生效(比如 ::before),如需兼容,得用真实子元素代替伪元素,并确保其宽高撑满父容器。
立即学习“前端免费学习笔记(深入)”;
- 移动端 Safari 对
transform: scale()+opacity合成层优化好,但若同时 animatingbackground-color,可能掉帧 - 不要给遮罩层设
pointer-events: none后又指望 hover 生效——父容器必须承载 hover 状态 - 如果扩散后要显示文字,文字元素需设
transform: translateZ(0)强制 GPU 加速,防闪烁
完整可复用结构:一个带背景渐变+文字浮现的遮罩示例
下面是最小可靠结构,复制即用,已避开常见陷阱:
.card {
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(135deg, rgba(0,0,0,0.8), rgba(0,0,0,0.2));
opacity: 0;
transform: scale(0);
transform-origin: center;
transition: opacity 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.card:hover::before {
opacity: 1;
transform: scale(1);
}
.card .caption {
position: absolute;
bottom: 1rem; left: 1rem;
color: white;
opacity: 0;
transform: translateY(10px);
transition: opacity 0.3s 0.15s, transform 0.3s 0.15s;
}
.card:hover .caption {
opacity: 1;
transform: translateY(0);
}
注意:transform-origin: center 必须写在未 hover 的状态里,否则 hover 时 origin 会跳变;transition-delay 只用于文字浮现,不用于遮罩本身。
容易被忽略的细节:overflow 和 z-index 的隐性冲突
如果父容器有 overflow: hidden(比如卡片带圆角),而遮罩层用 scale(1) 后实际尺寸略超(因 subpixel 渲染或字体度量误差),边缘可能被裁切。此时不要调大 scale,而是给遮罩层加 will-change: transform 并微调 top/left 偏移(如 -1px)来对齐。
另一个坑:遮罩层和内容文字都在同一 stacking context,若中间插了其他 z-index 元素(比如图标组件),文字可能被盖住。务必确认遮罩层的 z-index 高于所有同级内容,但低于弹窗类浮层。
- 不用
scale(1.01)强行撑满——它会让模糊滤镜失效、文字发虚 - 调试时临时加
outline: 1px solid red到遮罩层,能快速看清边界是否对齐 - 如果用
clip-path替代 scale 实现扩散,注意 Firefox 对clip-path: circle()的 hover 动画支持不稳定,慎用


















