hover切换无动画因filter默认不可过渡,须显式声明transition: filter 0.3s ease,并统一用grayscale(1)→grayscale(0)小数写法,避免单位混用、!important覆盖及IE/旧iOS Safari不支持导致失效。
filter: grayscale() 是最直接的方案,但直接写就跑不起来——浏览器兼容性、过渡动画、视觉失真这三关,一个没踩准就白忙。因为 filter 默认不可过渡,必须显式声明 transition 且参数要匹配:
transition: all 0.3s 不可靠,某些浏览器会忽略 filter 的插值transition: filter 0.3s ease
grayscale() 值,比如 grayscale(1) → grayscale(0),不能一边是 grayscale(100%) 一边是 grayscale(0)(单位混用可能中断动画)!important 覆盖 hover 状态,动画也会失效现代浏览器基本都支持,但细节决定成败:
IE 完全不支持,连降级提示都没有,直接忽略整条声明iOS Safari 9.3+ 才开始支持;低于此版本(比如微信 X5 内核早期版本)会静默失效@supports (filter: grayscale()) 更稳妥这不是 bug,是滤镜触发子像素重采样导致的,默认抗锯齿行为在高 DPR 屏幕或缩放下尤其明显:
image-rendering: -webkit-optimize-contrast(WebKit)或 image-rendering: crisp-edges(Firefox / Chrome 122+)能缓解,但 PNG 可能出现锯齿transform: scale(0.999),它会让 filter 强制走临时渲染缓冲,反而加剧模糊<img> 同时设 filter 和 object-fit: cover:裁切区域外的像素仍参与滤镜计算,扩大模糊范围filter 的硬件加速策略收紧,大量元素同时加 grayscale() 容易触发合成层爆炸,滚动卡顿两者等价,但实际开发中建议统一用小数:
立即学习“前端免费学习笔记(深入)”;
grayscale(1) 和 grayscale(100%) 渲染结果一致,但 JS 动态控制时传 0.7 比拼字符串 "70%" 更安全grayscale(2) 或负值——超出 [0, 1] 范围的值会被截断为 1,无效还误导人grayscale(1) ≠ “纯黑白色”,只是去色,灰阶分布由原图亮度决定;想强化反差,得叠加 contrast(1.3) 和 brightness(1.1),且顺序必须是先 grayscale 再调对比度,否则残留颜色会被拉伸失真filter: grayscale(1),而是知道什么时候该加 @supports,什么时候该砍掉 scale(0.999),以及为什么明明写了 transition 却没动——这些点藏在文档缝隙里,但线上一出问题,第一个崩的就是它。