用box-shadow模拟光泽应避免radial-gradient,核心是双层阴影:浅色inset高光+深色outset暗边,通过mousemove动态微调offset-x/y(±2px内),缓存getBoundingClientRect提升性能,移动端需禁用以防误触和掉帧。

用 box-shadow 模拟光泽,别碰 radial-gradient 做反光
纯 CSS 卡片光泽效果,核心不是画一个光斑,而是用多层 box-shadow 模拟高光+边缘柔化。很多人一上来就查 radial-gradient 覆盖一层白色圆斑,结果光斑死板、不随鼠标动、缩放失真——那不是光泽,是贴图。
真正轻量且响应式的做法是:固定卡片背景色 + 动态阴影偏移。关键在阴影的 x 和 y 值随鼠标位置微调,配合 inset 内阴影强化立体感。
-
box-shadow至少两层:一层浅色inset模拟顶部高光,一层深色outset模拟底部暗边 - 鼠标移动时只改
box-shadow的前两个参数(offset-x和offset-y),其余保持不变 - 偏移量控制在 ±2px 以内,超过 3px 就像卡片在抖,不是光泽是错位
监听 mousemove 计算相对坐标,别用 getBoundingClientRect() 每次重算
卡片内部光泽要“跟手”,就得知道鼠标离卡片左上角有多远。但每次事件都调用 getBoundingClientRect() 性能差,尤其卡片多或滚动频繁时会掉帧。
正确做法是在鼠标进入卡片时缓存一次边界,后续只用 event.clientX - rect.left 算相对 X,同理算 Y。再把结果映射到 -2~2 的偏移区间,直接塞进 box-shadow。
立即学习“前端免费学习笔记(深入)”;
- 用
element.addEventListener('mouseenter', () => { rect = element.getBoundingClientRect(); })缓存一次 - 在
mousemove里直接用rect,避免重复布局计算 - 映射公式建议用
(x - rect.left) / rect.width * 4 - 2,保证光斑始终在卡片内可感范围
移动端必须关掉光泽,否则误触+耗电
手机没鼠标,靠触摸模拟 mousemove 不仅不准,还会触发大量无意义重绘。iOS Safari 尤其敏感,连续触发阴影更新可能让页面变卡。
- 加判断:
if ('ontouchstart' in window || navigator.maxTouchPoints > 0),直接跳过绑定 - 或者用
@media (hover: none)在 CSS 里禁用所有:hover相关光泽样式 - 千万别在移动端 fallback 成“点击闪一下”,用户点的是按钮,不是找高光
光泽失效常见原因:父容器 overflow: hidden 或 transform 截断阴影
阴影被裁掉,八成不是代码写错,而是卡片外层有个 overflow: hidden 的 wrapper,或者用了 transform: scale(0.98) 类似操作——这两者都会创建新的层叠上下文,把 box-shadow 关在里面出不来。
- 检查卡片直系父元素的
overflow值,改成visible或留足阴影余量(比如 padding) - 如果必须用
transform,给卡片自身加will-change: transform,或换用scale配合transform-origin微调 - Chrome DevTools 里选中卡片,在 Styles 面板搜索
box-shadow,看预览小窗是否显示完整;不显示就说明被截了
光泽最麻烦的从来不是怎么亮起来,而是怎么让它只在该亮的地方亮、该停的时候停、换了设备还不闹脾气。细节都在偏移量范围、事件绑定时机和层叠上下文里。



















