从内部作用域覆盖:root CSS变量

问题描述 投票:10回答:3

在堆栈溢出的design system中,我们使用Less来编译CSS颜色值。

[我们在:root处声明了像@orange-500这样的全局变量,这些变量经常针对悬停状态,建筑物边框样式,背景颜色等进行修改

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

[当变量的作用域为CSS类时,此示例覆盖hsl中颜色的明度值的方法有效:

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

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

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

我尝试从:root切换到htmlbody时没有任何运气。有任何解决方法吗?

css scope css-variables
3个回答
2
投票

我想知道是否有比该解决方案更理想的方法,但是作为一种可能的解决方法,您可以进一步分解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));
}
<div class="card">
  Hello world
</div>

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


0
投票

这是一个范围界定问题。这样做是从--orange继承:root--orange中的:root亮度为68%。

为了进行更改,您需要将--orange变量重新定义为一个元素,该元素将查找新的--lightness值。有几种方法可以实现:

选项1:在元素上复制--orange变量:

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

  --lightness: 45%;
}
<div class="card">
  Hello world
</div>

显然,这有点臭,因为您将不得不复制该--orange变量。

选项2:您可以抽象--orange的其他参数,以免重复。尽管它是更多文本,但我还是会喜欢这种方法:

: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%;
}
<div class="card">
  Hello world
</div>

您可以要做的是,将其专门作用于可能应用于HTML元素或正文的.darkMode类。这也可能是有道理的,因为很清楚代码的意图是:

选项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));
}
  <div class="darkMode">
    <div class="card">
      Hello world
    </div>
  </div>

不管您怎么走,问题是--orange变量是从设置了--lightness的原始范围继承的。将其视为“继承计算值”。

为了获得--orange以获得新的亮度,您需要在某处添加新的--orange

选项4

我不确定您的主题模式是什么,但是我可以解释一下如何以我自己的blog创建暗模式。如果您查看CSS,将会看到我创建了两个遵循相同命名约定的完整主题:

--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);

然后我要做的是创建一个第三变量集,其作用是成为“主动”管理者:

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

然后,我将活动主题设置限制在一个类下:

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

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


0
投票

简单的解决方案是将CSS变量放入单独的CSS文件中,然后根据需要将其换出。例如,支持暗模式的媒体查询可以进行交换,也可以使用JavaScript,预烘焙主题等。

关于此事的好处是,将CSS文件与变量定义交换会实时更改CSS呈现。

假设您正在将媒体查询用于亮/暗模式。如果浏览器理解并请求“暗模式”,则仅加载第一个文件。但是,如果浏览器无法理解这些媒体查询,则由于两个CSS文件均已加载,但后续规则将覆盖先前的规则

<link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="/light.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)">
<!-- The main stylesheet -->
<link rel="stylesheet" href="/style.css">

在这些样式表中,您想使用:root伪类,因为它与HTML基本相同,但是在大多数浏览器中具有更高的特异性。

light.css

:root {
  --text-color: #333;
  --background-color: #fff;
}

dark.css

:root {
  --text-color: #dadada;
  --background-color: #333;
}

另外,请注意,如Travis在该答案中所提到的,简化变量并在元素内部构建完整规则是一个好主意。

style.css(主要样式文档)

body {
  color: var(--text-color);
  background-color: var(--background-color);
}

作为旁注,您可能想在CSS read属性上单击color-scheme,以获取对本机浏览器元素的更好支持。

© www.soinside.com 2019 - 2024. All rights reserved.