【问题标题】:Overriding :root CSS variables from inner scopes [duplicate]覆盖:内部范围的root CSS变量[重复]
【发布时间】:2020-02-01 01:10:30
【问题描述】:

在 Stack Overflow 的 design system 中,我们使用 Less 来编译 CSS 颜色值。

我们有全局 Less 变量,例如 @orange-500,经常针对悬停状态、构建边框样式、背景颜色等进行修改。

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

这个在hsl 中覆盖我们颜色的亮度值的示例适用于将变量范围限定为 CSS 类的情况:

.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 没有任何运气。有什么解决方法吗?

【问题讨论】:

  • 一开始看起来很奇怪,但是当你真正开始理解它时,当一个东西悬停时,橙色在页面上变化是否有意义?
  • 目的是在.card:hover的上下文中获取全局橙色并通过x量修改其亮度。
  • 是的,我明白了,我只是说一旦你意识到:root 中定义的--lightness 是一个全局变量,而.card:hover 中定义的--lightness 是一个局部变量行为符合预期,因为--orange' references the global --lightness` 不是本地的--lightness
  • 简短回答:这是不可能的。如果在 :root 中使用了 var() 则结束,它已经针对所有 DOM 进行了评估

标签: css scope css-variables


【解决方案1】:

我很想知道是否有比这个解决方案更理想的方法,但作为一种可能的解决方法,您可以进一步分解您的 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 时做更多工作前端。

【讨论】:

    【解决方案2】:

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

    这样做的好处是用您的变量定义交换 CSS 文件会实时更改 CSS 呈现。

    假设您将媒体查询用于明/暗模式。如果浏览器理解并请求“暗模式”,则仅加载第一个文件。但是,如果浏览器不理解这些媒体查询,您的“默认”是 light.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 color-scheme 属性上添加 read 以获得对原生浏览器元素的更好支持。

    【讨论】:

      【解决方案3】:

      这是一个范围界定问题。你这样做的方式是从:root 继承--orange,而:root 中的--orange 的亮度为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);
      }
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多