从内部范围覆盖:root CSS变量

Aar*_*key 11 css scope css-variables

在Stack Overflow的设计系统中,我们使用Less来编译CSS颜色值。

我们有类似@orange-500这样的全局Less变量,这些变量经常针对悬停状态,建筑边框样式,背景颜色等进行修改。

在Less中,它写为darken(@orange-500, 5%)。我正在尝试使用本机CSS变量实现类似的目的。切换到CSS变量将使我们能够更快地发布依赖主题的功能(堆栈交换网络,暗模式等),使用更少的CSS行,同时在媒体查询上启用变量交换(高对比度,暗模式等) )。

hsl当变量的作用域为CSS类时,此示例将在工作中覆盖颜色的明度值:

.card {
  --orange: hsl(255, 72%, var(--lightness, 68%));
  background: var(--orange);
}
.card:hover {
  --lightness: 45%;
}
Run Code Online (Sandbox Code Playgroud)
<div class="card">
  Hello world
</div>
Run Code Online (Sandbox Code Playgroud)

但是,我们需要在一个可交换的位置上全局指定颜色变量,以支持全局主题设置,但这并不能按预期工作:

:root {
  --orange: hsl(255, 72%, var(--lightness, 68%));
}
.card {
  background: var(--orange);
}
.card:hover {
  --lightness: 45%;
}
Run Code Online (Sandbox Code Playgroud)
<div class="card">
  Hello world
</div>
Run Code Online (Sandbox Code Playgroud)

我试图从切换:roothtmlbody没有任何的运气。有什么解决方法吗?

Tra*_*ton 5

我有兴趣了解是否有比此解决方案更理想的方法,但作为一种可能的解决方法,您可以进一步分解 CSS 变量并在元素样式定义中构建值,如下所示:

:root {
  --orangeColor: 37,72%;
  --redColor: 1,72%;
  --blueColor: 215,72%;
  --greenColor: 126,72%;
  
  --LumDefault: 68%;
  --LumDark: 45%;
  --LumLight: 80%;
}
.card {
  background: hsl(var(--orangeColor), var(--LumDefault));
}
.card:hover {
  background: hsl(var(--orangeColor), var(--LumDark));
}
.card:active {
  background: hsl(var(--redColor), var(--LumDark));
  color: hsl(var(--greenColor), var(--LumLight));
}
Run Code Online (Sandbox Code Playgroud)
<div class="card">
  Hello world
</div>
Run Code Online (Sandbox Code Playgroud)

我确实意识到这并没有像您想要完成的那样覆盖,但是从您所说的业务案例来看,它将为您提供一种在全局级别管理元素的方法……只是在前端定义 CSS 时需要做更多工作.


pac*_*aux 5

This is a scoping issue. The way you're doing it, you're inheriting --orange from the :root, and --orange in the :root has a lightness of 68%.

In order to change it, you'll want to re-scope the --orange variable to an element that will look up the new --lightness value. There's a few ways to pull this off:

Option 1: duplicate the --orange variable on the element:

:root {
  --lightness: 68%;
  --orange: hsl(255, 72%, var(--lightness));
}
.card {
  background: var(--orange);
  --orange: hsl(255, 72%, var(--lightness));
}
.card:hover {

  --lightness: 45%;
}
Run Code Online (Sandbox Code Playgroud)
<div class="card">
  Hello world
</div>
Run Code Online (Sandbox Code Playgroud)

Obviously this kinda stinks, because you're going to have to duplicate that --orange variable.

Option 2: You could abstract the other parameters of --orange so that it's not as duplicative. I'd be a fan of this approach despite the fact that it's more text:

:root {
  --lightness: 68%;
  --orangeHue: 255;
  --orangeSat: 72%;
  --orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
.card {
  background: var(--orange);
  --orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
.card:hover {

  --lightness: 45%;
}
Run Code Online (Sandbox Code Playgroud)
<div class="card">
  Hello world
</div>
Run Code Online (Sandbox Code Playgroud)

What you could also do is scope this specifically to a .darkMode class that might be applied to the HTML element or the body. This could also make sense because it's clear what the intent is from the code:

Option 3

:root {
  --lightness: 68%;
  --orangeHue: 255;
  --orangeSat: 72%;
  --orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}

.card {
  background: var(--orange);

}
.card:hover {
  --lightness: 45%;
}
.darkMode .card {
  --orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
Run Code Online (Sandbox Code Playgroud)
  <div class="darkMode">
    <div class="card">
      Hello world
    </div>
  </div>
Run Code Online (Sandbox Code Playgroud)

Regardless of how you go, the issue is that the --orange variable is inheriting from its original scope where --lightness is set. Think of it as "inheriting a computed value".

In order to get --orange to get the new lightness, you need a new --orange somewhere.

Option 4

I'm not sure what your theme pattern is, but I can explain how I created a dark mode on my own blog . If you look at the CSS What you'll see is that I've created two complete themes that follow the same naming convention:

--themeLightTextColor: rgb(55, 55, 55);
--themeLightBGColor: rgb(255, 255, 255);
--themeLightAccentColor: rgb(248, 248, 248);
--themeLightTrimColor: rgb(238, 238, 238);
--themeDarkTextColor: rgb(220, 220, 220);
--themeDarkBGColor: rgb(23, 23, 23);
--themeDarkAccentColor: rgb(55, 55, 55);
--themeDarkTrimColor: rgb(40, 40, 40);
Run Code Online (Sandbox Code Playgroud)

What I then do is create a third set of variables whose job it is to be the "active" managers:

--themeActiveLinkColor: var(--linkColor);
--themeActiveLinkColorHover: var(--linkColorHover);
--themeActiveTextColor: var(--themeLightTextColor);
--themeActiveEditorialTextColor: var(--themeLightPltNLow);
--themeActiveBGColor: var(--themeLightBGColor);
--themeActiveAccentColor: var(--themeLightAccentColor);
--themeActiveTrimColor: var(--themeLightTrimColor);
Run Code Online (Sandbox Code Playgroud)

Then, I scope the active theme settings under a single class:

.theme--dark {
   --themeActiveTextColor: var(--themeDarkTextColor);
   --themeActiveEditorialTextColor: var(--themeDarkPltNLow);
   --themeActiveBGColor: var(--themeDarkBGColor);
   --themeActiveAccentColor: var(--themeDarkAccentColor);
   --themeActiveTrimColor: var(--themeDarkTrimColor);
}
Run Code Online (Sandbox Code Playgroud)

似乎您的意图是不必显式声明主题,而可以调整一些“根变量”来进行调整。但我建议也许您有一个模式,一个班级可以改变一个活跃的主题。这种模式的优点是您还可以调整类名上的所有“根变量”。