gpt4 book ai didi

javascript - 为类和媒体查询定义暗模式,无需重复 CSS 自定义属性声明,并允许用户在颜色模式之间切换

转载 作者:行者123 更新时间:2023-12-05 00:34:42 25 4
gpt4 key购买 nike

我有:

body { background: white; }
为了显示暗模式,我使用 .dark类(class):
.dark body { background: black; }
为了检测用户的操作系统是否设置为使用深色主题,我们有 prefers-color-scheme :
@media (prefers-color-scheme: dark) {
body { background: black; }
}
然后我们有了 DRY(不要重复自己)编程的想法。我们能否在不重复 CSS 属性声明的情况下定义暗模式, 并在过程中 ,允许用户通过JS在颜色模式之间切换?
在上面的例子中, .dark类和媒体查询是彼此的副本。
到目前为止我所做的
跳过 prefers-color-scheme在 CSS 中并使用:
body { background: white; }
.dark body { background: black; }
然后通过JS,检测它们的设置并调整
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.getElementsByTagName('html')[0].classList.add('dark');
}
这种方法的问题是它不使用 prefers-color-scheme在 CSS 中。
虽然我可以添加:
@media (prefers-color-scheme: dark) {
body { background: black; }
}
它不会让我 切换 通过 JS 的配色方案,因为我无法取消 prefers-color-scheme: dark对于在其操作系统首选项中设置了深色的用户。
2022 年解决这个问题的方法是什么?

最佳答案

我们来分析一下。
我们绝对不能只将暗模式样式放在媒体查询中,因为无法通过现场选择来应用它。所以我们希望样式在某个类( dark )下,没有媒体查询(以便可以通过 JS 切换该类),但媒体查询应该以某种方式提取相同的样式,即使没有该类,并且不重复样式。我们可能还想要一个 light如果用户选择覆盖媒体查询的类。
这里的完美解决方案是废弃的 @apply at-rule这可以允许在单个变量下重用一堆样式。但这是,好吧,被放弃了。
重用一堆样式的标准建议是在 CSS 预处理器上使用 mixin(因此它不会在元素的源代码中重复,但会在编译后的 CSS 上重复)。如果所有属性都应用于 <body>元素或几个元素然后我相信这是要走的路。但是,您要求没有预处理器的解决方案。
另一种方法是在 JS 中而不是在 CSS 本身中使用媒体查询,并相应地切换类。此方法甚至可以处理具有应用于许多元素的属性的复杂主题,但它可能具有 "Flash of unstyled content"直到 JS 生效。无论如何,您已经提出了这个问题,并要求提供一种将媒体查询保留在 CSS 本身中的解决方案。
您还要求不要使用重复的 CSS 变量。现在,我不确定是否可以不重复任何内容,但是我们可以将重复减少到两个“切换”变量,而不管受影响属性的数量。

var root = document.documentElement,
theme = window.getComputedStyle(root)
.getPropertyValue('--light') === ' ' ? 'dark' : 'light';

document.getElementById('toggle-theme')
.addEventListener('click', toggleTheme);

function toggleTheme() {
root.classList.remove(theme);
theme = (theme === 'dark') ? 'light' : 'dark';
root.classList.add(theme);
}
/*
"initial"ized variables are like undefined variables and will resolve to
their fallback value.
Whitespaced variables (the space is required) will serve as an empty value
in chaining.
*/

@media (prefers-color-scheme: dark) {
:root {
--light: ;
--dark: initial;
}
}

@media (prefers-color-scheme: light) {
:root {
--dark: ;
--light: initial;
}
}

:root.dark {
--light: ;
--dark: initial;
}

:root.light {
--dark: ;
--light: initial;
}

#content {
background-color: var(--dark, darkblue) var(--light, lightblue);
color: var(--dark, white) var(--light, black);
border: 5px solid var(--dark, blue) var(--light, yellow);
}
<div id="content">
Hello, world!
<button id="toggle-theme">Toggle theme</button>
</div>

最后,我可以想到另一种可能的破解方法,尽管我真的不喜欢它。这个想法是添加两个 <div> s 的唯一目的是根据首选/选定的主题将样式继承到另一个。

var root = document.documentElement,
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';

document.getElementById('toggle-theme')
.addEventListener('click', toggleTheme);

function toggleTheme() {
root.classList.remove(theme);
theme = (theme === 'dark') ? 'light' : 'dark';
root.classList.add(theme);
}
.dark-styles {
background: darkblue;
color: white;
border-color: blue;
}

.light-styles {
background: lightblue;
color: black;
border-color: yellow;
}

:root.dark .light-styles {
all: inherit;
}

@media (prefers-color-scheme:dark) {
:root:not(.light) .light-styles {
all: inherit;
}
}

#content {
border: 5px solid;
border-color: inherit;
}
<div class="dark-styles">
<div class="light-styles">
<div id="content">
Hello, world!
<button id="toggle-theme">Toggle theme</button>
</div>
</div>
</div>

关于javascript - 为类和媒体查询定义暗模式,无需重复 CSS 自定义属性声明,并允许用户在颜色模式之间切换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70845195/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com