CSS Light/Dark Mode实现无复制VAR
#css #网络开发人员 #教程 #howto

在CSS中实施光模式和暗模式切换背后的挑战的一个普遍观点是,它似乎需要复制您的-var声明才能设置类。

不是 - 它是一个很容易实现的模式!


一个简短的历史

举例来说,this article from Bramus在2022年5月指出了共同的观点:

Screenshot of an excerpt from the article linked above showing a warning from the author that duplication is necessary, plus the CSS code to demonstrate it

尽管在撰写该文章时,它被广泛地接受为真理,但围绕复制 [1] 的实际主题颜色价值有很多方法,这是关注点的大部分。但是...这些方法也留出了改进的空间。

找到了改进,并在所有浏览器中工作 [2] - 除了Safari -until Safari 16.4, around March 2023开始在任何地方工作时!

ps:Bramus is great, follow him!


所需的API

首先,社区最大的问候是,我们可以从实际的媒体偏好中完成所有这些,而无需复选框黑客攻击或使JS在负载上切换以翻转状态,而that work is underway now

与此同时,即使在实施之后,也很高兴拥有除了偏好之外管理课程的灵活性。

这是API:

  • 默认情况下黑暗
  • @media (prefers-color-scheme: light) root and of of of preference
  • .theme-preferred基于默认的root preferference渲染此节点(&desc。)
  • .theme-not-preferred将此节点(&desc。)渲染为默认根本偏好的对立
  • .theme-dark在黑暗中呈现此节点(&desc。)
  • .theme-light在光中渲染此节点(&desc。)

然后,将其混合并匹配该API。任何部分或元素,无论父母或偏好是什么,您都可以通过偏好或直接管理光/黑暗来切换。

例如,这将完全按照预期的方式渲染:

<div class="theme-dark">
  <span>render dark</span>
  <div class="theme-light">render light</div>
</div>

这也是如此:

<main class="theme-preferred">
  preferred theme here even if body or html changed it
  <div class="theme-light">light</div>
  <div class="theme-dark">dark</div>
  <section class="theme-not-preferred">
    render the opposite of the preference
    <div class="theme-preferred">render the preference</div>
    <div class="theme-light">light</div>
    <div class="theme-dark">dark</div>
  </section>
</main>

干燥的实施

如果您不熟悉太空切换,则可以在没有任何技术知识的情况下复制粘贴此设置;初始设置后您不必使用它们。

遵循模式将使您充分利用它!

如果您有兴趣,you can read about space toggles here from when I first invented the idea或Google Google以自那时以来就已经出现的许多文章和演讲!

简而言之,您将灯开关添加到其他值。如果开关是一个空间(ON),则使用旁边的值,如果是initial(off),则未使用该值,而后备将其放置在引用时。

(是的,是规格!)

样板

首先,将其完全按原样复制。无论您需要在主题之间切换多少个变量,此引擎都不会改变并且完成所有工作:

.theme-not-preferred,
.theme-light {
  --media-prefers-light: ;
}
.theme-preferred,
.theme-dark {
  --media-prefers-light: initial;
}
@media (prefers-color-scheme: light) {
  :root,
  .theme-preferred {
    --media-prefers-light: ;
  }
  .theme-not-preferred {
    --media-prefers-light: initial;
  }
}

这设置了一个--media-prefers-light空间切换,该切换按照前面描述的我们所需的API翻转。 (互相设置和空间切换是彼此进行的;请查看css-media-vars,以获取整体收集以及它们提供的巨大改进!)

您的主题价值观

接下来,我们将仅设置3个主题依赖性变量来建立模式:

:root,
.theme-preferred,
.theme-not-preferred,
.theme-light,
.theme-dark {
  /* (toggle) + Light Values: */
  --theme_0_light: var(--media-prefers-light) 0 0% 100%;
  --theme_1_light: var(--media-prefers-light) 0 0% 0%;
  --theme_2_light: var(--media-prefers-light) hotpink;

  /* (toggled_light_value, fallback to Dark Values */
  --theme-0: var(--theme_0_light, 0 0% 0%);
  --theme-1: var(--theme_1_light, 0 0% 100%);
  --theme-2: var(--theme_2_light, rebeccapurple);
}

您不会直接使用--theme_1_light的光var,它们仅是内部var(因此强调命名约定)来设置您实际想在任何地方使用的var,--theme-1等。

用法

最后,您要做的就是在CSS中使用主题变量:

.my-info-box-component {
  background: hsl(var(--theme-0));
  color: hsl(var(--theme-1));
  border: 1px solid var(--theme-2);
  padding: 1rem;
}

然后,它在所有API方案中都可以在您的HTML中工作:

<aside class="my-info-box-component">
  My border is:<br>
  - `hotpink` with light mode preference<br>
  - `rebeccapurple` with dark mode preference.
</aside>

和:

<aside class="my-info-box-component theme-not-preferred">
  My border is:<br>
  - `rebeccapurple` with light mode preference<br>
  - `hotpink` with dark mode preference.
</aside>

和这个:

<section class="theme-not-preferred">
  ...
  <aside class="my-info-box-component">
    My border is:<br>
    - `rebeccapurple` with light mode preference<br>
    - `hotpink` with dark mode preference.
  </aside>
  ...
  <aside class="my-info-box-component theme-preferred">
    My border is:<br>
    - `hotpink` with light mode preference<br>
    - `rebeccapurple` with dark mode preference.
  </aside>
</section>

当然也是:

<aside class="my-info-box-component theme-dark">
  My border is `rebeccapurple`
</aside>

<section class="theme-dark">
  <div>
    ...
    <div>
      ...
      <div>
        ...
        <aside class="my-info-box-component">
          My border is `rebeccapurple`
        </aside>
        ...
      </div>
      ...
    </div>
    ...
  </div>
</section>

方案测试 /演示Codepen


结束!

如果您认为这很有用,那是我一直很开心的事情!因此,请考虑在这里关注我and on X

ð½ð
//简·奥里

ps:我最近被解雇了,正在寻找工作!

https://linkedin.com/in/JaneOri

在13年的完整堆栈(主要是JS)工程工作和咨询中,为正确的机会做好了准备!


[1]“围绕复制的方式” - 如果您想要像本文所示的Space Toggle驱动API一样,您确实必须重复一些可变工作,但是可以避免主要关注的问题;实际主题颜色值无重复。 DRY Theme color values, version that works in all browsers

[2]改进的版本“在除Safari以外的所有浏览器中都起作用” - 本文中描述的方法在Firefox和Chrome中工作了很多年,但是因为Safari从技术上可以根据CSS Spec,FF&对其进行正确的处理。 Chrome“修复”以彼此协调(因此所有3个主要浏览器都处于和谐相处),然后为了响应I filed an issue以更改规格,成功地使所有各方同意(再次打破和谐),CSS规格更改了以描述以前作为新规格的行为,FF和Chrome在步骤中恢复为先前的行为,AAAND SAFARI稍后更新,从而产生了新的,改进的,和谐!