css变量在暗黑模式下图片滤镜不一致,根本原因是filter未绑定变量或变量未在:root和[data-theme="dark"]中双重定义;需统一用--img-brightness驱动img、背景容器、svg image,并将亮度安全值控制在0.8–0.9之间。

CSS 变量在暗黑模式下图片滤镜不一致,根本不是变量“没生效”,而是 filter 没绑定到变量、或变量没被正确覆盖。 直接写 filter: brightness(0.85) 或只在 :root 定义一次 --img-brightness,都会导致切换主题时滤镜卡死、跨设备表现不一。
为什么 filter: brightness(var(--img-brightness)) 有时还是不动
常见现象是:HTML 加了 data-theme="dark",控制台里 getComputedStyle(img).filter 却始终显示 brightness(1)。这不是 JS 没触发,而是 CSS 层叠链断了。
-
--img-brightness必须在:root和[data-theme="dark"]两个作用域里都定义,不能只靠媒体查询——prefers-color-scheme在 SSR 或首屏渲染时不可靠,data-theme是唯一可控入口 - 别把
[data-theme="dark"]写成.dark或html.dark,除非你 JS 明确加的是那个 class;否则变量根本不会被覆盖 - 确保图片元素上没其他规则写了
filter: none或更高优先级的filter值,它们会直接屏蔽变量计算结果
如何让 img、背景图、SVG 同时响应同一套变量
三者写法不同,但目标一致:所有滤镜必须通过同一个 --img-brightness 变量驱动,否则维护成本爆炸。
-
<img>:直接加 class,比如<img class="themed-img">,CSS 里写.themed-img { filter: brightness(var(--img-brightness)); } - 背景图:给父容器加 class(如
<div class="bg-cover">),再对这个容器设 <code>filter;background-filter几乎不用,Safari 16+ 才实验性支持 - SVG
<image></image>:必须在<image></image>标签上写filter,且要确保preserveAspectRatio="xMidYMid meet",否则缩放后滤镜形变 - 亮色模式下保持
--img-brightness: 1,暗黑模式从0.85起步,极少需要低于0.8;0.7已经接近视觉塌陷临界点 - 别用
brightness(0)或负值——规范不支持,Chrome/Safari 会静默忽略,变成默认亮度 - 夜景图、深色插画等本就偏暗的图片,在暗黑模式下可设为
1,甚至配合contrast(1.05)提层次,而非强行压暗 - 加
backface-visibility: hidden到图片选择器里,能强制走更精准的光栅化路径,解决文字/图标边缘半像素模糊 - 仅对高频切换的图片加
will-change: filter,否则耗电;普通静态图不需要 - 避免在
<picture></picture>上直接写filter,它不继承,应作用于内部<img>
brightness() 的安全取值和典型误用
很多人试过 brightness(0.7) 发现图片发闷、细节糊成一片,这不是参数错了,是人眼在暗背景下对低亮度区域极度敏感。
为什么 iOS Safari 里图片滤镜会闪、文字边缘发虚
这不是 bug,是 GPU 合成策略导致的渲染路径切换。尤其在 position: fixed 容器或频繁切换场景下更明显。
真正难的不是写几行 CSS,而是在所有图片载体(img、背景容器、SVG image)上统一变量入口,并守住 0.8–0.9 这个窄得反直觉的亮度安全带——稍低就糊,稍高就刺眼,且无法靠“多试几次”蒙出来。











