在切换到浅色模式时让背景颜色反转

前端开发 2026-07-09

我正在开发一个使用Catppuccin主题系统的网站。深色模式工作正常,但在浅色模式(Latte)下,背景图片的渲染始终有问题。

我的默认样式表使用一个 body::before 伪元素来显示一个SVG背景。

风格(主题变体)通过某些JS设置在 <html> 上的一个 data-flavor 属性,它在四种Catppuccin变体之间循环,Latte是其中的浅色版本。

在我的Latte样式表中,CSS变量设置得很好,能够工作。但我尝试为浅色模式覆盖背景伪元素的做法没有正确渲染。

到底哪里出错了?

最小可复现示例:

<!DOCTYPE html>
<html data-flavor="mocha">
<head>
<style>
  /* Minimal Catppuccin-style variables */
  html[data-flavor="mocha"] { --base: #1e1e2e; --text: #cdd6f4; }
  html[data-flavor="latte"] { --base: #eff1f5; --text: #4c4f69; }

  body {
    margin: 0;
    background: var(--base);
    color: var(--text);
    font-family: sans-serif;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
  }

  /* Default (dark) background watermark */
  body::before {
    content: "";
    position: fixed;
    inset: 0;
    background: url(https://upload.wikimedia.org/wikipedia/commons/0/00/Estradiol.svg) center / cover no-repeat;
    filter: invert(86%) sepia(8%) saturate(900%) hue-rotate(190deg) brightness(105%);
    opacity: 0.05;
    pointer-events: none;
  }

  /* Attempted light-mode override — this is the broken part */
  body::before[data-flavor="latte"] {
    background: url(https://upload.wikimedia.org/wikipedia/commons/0/00/Estradiol.svg) center / cover no-repeat;
    filter: invert(1);
  }
</style>
</head>
<body>
  <div>
    <p>Background watermark should be <strong>light</strong> in Mocha, <strong>dark</strong> in Latte.</p>
    <button onclick="document.documentElement.setAttribute('data-flavor','mocha')">Mocha (dark)</button>
    <button onclick="document.documentElement.setAttribute('data-flavor','latte')">Latte (light)</button>
  </div>
</body>
</html>

解决方案

正如评论中所建议的,

body::before[data-flavor="latte"]

在语法上是无效的;[attribute] 必须位于(可选的)元素与其伪内容之间:

body[data-flavor="latte"]::before

此外,你的测试 invert(1) 会使图像变白,实质上与近白色背景 #eff1f5 看起来没有区别。

如果你计划在任一明暗方案中只使用单一颜色主题,我建议不再使用数据属性,而是直接利用 color-scheme 的内联样式应用于 html。为调色板的明暗度明确对应一个 color-scheme 本身是有好处的:这会确保浏览器在渲染未经过样式处理的内容时表现更好(参见按钮和滚动条)。

此外,你还可以以一种方式利用自定义属性,让“变量”和它们的“应用”分离开来,这样主样式部分就不会分支;类似如下:

/* Minimal Catppuccin-style variables */
html {
  --base: #1e1e2e;
  --text: #cdd6f4;
  --background: url(https://upload.wikimedia.org/wikipedia/commons/0/00/Estradiol.svg);
  --background-filter: invert(86%) sepia(8%) saturate(900%) hue-rotate(190deg) brightness(105%);
}

html[style*="color-scheme: light;"] {
  --base: #eff1f5;
  --text: #4c4f69;
  /* Keeping the "default" pic */
  --background-filter: invert(30%);
}

body {
  background-color: var(--base);
  color: var(--text);
  font-family: sans-serif;
  &::before {
    background: var(--background) center / cover no-repeat;
    filter: var(--background-filter);
    pointer-events: none;
    content: "";
    position: fixed;
    inset: 0;
    opacity: 0.05;
  }
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 110vh; /* for showing the scrollbar colour change */
}
<html style="color-scheme: dark;">
<div>
  <p>Background watermark should be <strong>light</strong> in Mocha, <strong>dark</strong> in Latte.</p>
  <button
  onclick="document.documentElement.style.colorScheme='dark';">Mocha (dark)</button>
  <button
  onclick="document.documentElement.style.colorScheme='light';">Latte (light)</button>
</div>

你甚至可以通过省略“defaults”声明在“裸露的” html 上,让它更简洁,并把值直接放在具体应用的 var(…, fallback) 部分,例如:

background: var(--base, #1e1e2e);

但这感觉有点儿不干净……

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章