必须用 CSS 变量绑定 filter 参数,如 filter: brightness(var(--img-brightness)),否则 data-theme 切换时滤镜不更新;需在 :root 和 [data-theme="dark"] 中分别定义变量,配合 transition: filter 实现平滑过渡。

必须用 var(--filter-value) 绑定滤镜参数,不能写死数值;否则 data-theme 切换后 filter 不会重算。
为什么 brightness(0.7) 在暗黑模式下完全失效
不是 CSS 没加载,而是硬编码的 brightness(0.7) 是静态值,JS 修改 document.documentElement.setAttribute('data-theme', 'dark') 时,浏览器不会重新解析这个固定数字。它和主题变量毫无关联,相当于“贴死的胶布”,撕不下来也变不了形。
常见错误写法:
img { filter: brightness(0.7); }
正确思路是把亮度值抽成变量,让 CSS 层叠机制驱动更新:
立即学习“前端免费学习笔记(深入)”;
-
:root定义默认亮度:--img-brightness: 1; -
[data-theme="dark"]覆盖该变量:--img-brightness: 0.85; - 所有图片统一用:
filter: brightness(var(--img-brightness));
如何让 filter 响应 data-theme 切换
关键在选择器优先级和作用域。:root 提供初始值,[data-theme="dark"] 是更具体的选择器,能覆盖同名变量——这正是 CSS 变量生效的底层逻辑。
务必注意以下三点:
- 变量必须声明在
:root和[data-theme="dark"]两个地方,缺一不可;只写@media (prefers-color-scheme: dark)无法响应 JS 主动切换 - 操作目标只能是
document.documentElement,写document.body.setAttribute('data-theme', 'dark')完全无效 - 值必须是小写字符串
'dark'或'light',不能传true、1或'Dark'
组合滤镜时怎么避免失控
单用 brightness() 往往不够,常需搭配 contrast() 和 saturate() 来维持观感。但直接写死多个数值(如 filter: brightness(0.8) contrast(1.2) saturate(0.9))仍会断开主题联动。
推荐做法是为每个参数都设独立变量:
:root {
--img-brightness: 1;
--img-contrast: 1;
--img-saturate: 1;
}
[data-theme="dark"] {
--img-brightness: 0.85;
--img-contrast: 1.15;
--img-saturate: 0.95;
}
.themed-img {
filter: brightness(var(--img-brightness))
contrast(var(--img-contrast))
saturate(var(--img-saturate));
}
这样每项都可单独调试,也方便后续扩展(比如暗色模式下对特定图片微调饱和度)。
transition 过渡加在哪才真正起作用
filter 的过渡不会自动继承,必须显式声明。而且不能只写在 [data-theme="dark"] img 里——那个规则只在暗色激活时存在,亮色状态下无过渡。
正确位置是通用选择器:
- 给图片加过渡:
.themed-img { transition: filter 0.4s ease; } - 别用
transition: all,它会意外触发font-size或transform动画,导致布局抖动 - 如果页面有大量图片,建议加
will-change: filter提前提示 GPU 加速(但仅限必要场景)
最易被忽略的是:变量值本身没有“中间态”,过渡靠的是浏览器对 filter 属性值变化的插值计算——所以变量绑定和过渡声明必须同时到位,少一个就卡顿。


















