【问题标题】:How to fake css variables in scss?如何在scss中伪造css变量?
【发布时间】:2017-10-08 20:18:32
【问题描述】:

我对 css 变量进行了修改,找到了一个有趣的应用程序:您可以定义一个 --color 变量,并将其用作基于类的不同属性的值:按钮的背景可以用 @987654322 填充@,而选项卡控件可以使用带有--color 的边框底部来突出显示当前选项卡,如下所示:

:root {
  font: 14px sans-serif;
  --red: #f44;
  --blue: #78f;
  --green: #3c1;
  --color: var(--blue);
}

.blue {
  --color: var(--blue);
}

.red {
  --color: var(--red);
}

.green {
  --color: var(--green);
}

.fillbutton {
  background: var(--color);
  color: #fff;
  padding: 0.25em 1em;
}

.borderbutton {
  background: #fff;
  border: 1px solid var(--color);
  color: var(--color);
  padding: 0.25em 1em;
}

.tab {
  border-bottom: 1px solid #ccc;
  padding: 0 1em;
  line-height: 150%;
}

.tab.current {
  border-bottom: 2px solid var(--color);
  color: var(--color);
  font-weight: bold;
}
<p>
  <span class="fillbutton">Default</span>
  <span class="fillbutton green">Green</span>
  <span class="fillbutton red">Red</span>
  <span class="borderbutton">Default</span>
  <span class="borderbutton green">Green</span>
  <span class="borderbutton red">Red</span>
</p>

<p><span class="tab">Tab1</span><span class="tab current">Tab2</span><span class="tab">Tab3</span></p>

<p><span class="tab red">Tab1</span><span class="tab red current">Tab2</span><span class="tab red">Tab3</span></p>

通过定义类来改变 --color 我们可以轻松地创建不同的配色方案,而不必特定于我们想要样式的项目:只需要一个 .red 类,而不是单独的 .red.fillbutton/@987654328 @/.red.tab.current

由于某些浏览器不支持 css 变量,我想我会尝试使用像 scss 这样的处理器来复制这个功能,但是 scss 变量似乎只是全局的,因此无法模仿这个用例。有没有办法让我使用 scss 以类似的 DRY 方式实现上述行为?

【问题讨论】:

    标签: css sass css-variables


    【解决方案1】:

    由于通过 SCSS 生成 CSS 文件很容易,您可以拥有单独的颜色变量 SCSS 文件和主“导入”SCSS 文件(对于您可能拥有的所有其他 SCSS 文件)。然后你要做的是为每个颜色变量文件编译单独的 CSS 文件(例如,你可以有 3 个网站颜色主题,所以 3 个不同的颜色变量 SCSS 文件,然后是 3 个不同的输出文件)。当用户选择不同的主题时,您只需记住用户选择的主题(cookie)并通过 JS 加载适当的 CSS 文件,而不是硬编码要使用的 CSS 文件。

    它并不完全 DRY,因为您必须定义“主”输出 SCSS 文件(这些应包括导入适当的颜色变量 SCSS 文件,该文件会随每个文件而变化,以及“主导入”SCSS 文件的导入,这总是相同的)分别为每个颜色变量(所以如果你有 3 个颜色主题,你必须定义 3 个文件)——尽管它可能也可以通过编程方式完成。但是,这样您就可以启用网站的多种颜色主题,而不必担心当前缺乏对纯 CSS 变量的跨浏览器支持。只要您有预定义的颜色主题列表,这可能就是要走的路。

    如果您没有预定义的颜色主题列表,并且希望用户能够使用颜色选择器设置自己的颜色主题(并且不希望他们先提交这些值然后使用这些值,服务器-side,要从中生成一个 CSS 文件并将该文件获取给用户),您可以使用“currentColor”CSS 属性。它受支持并且可以用作颜色变量,尽管它在功能方面的限制比新的 CSS 变量要大得多。基本上,通过 currentColor 您可以访问父元素的 color 属性。因此,您可以为父母提供类和样式(例如,.blue 具有蓝色),然后通过 currentColour 设置几乎所有内容。然后,当用户通过颜色选择器或其他东西将蓝色更改为绿色时,您可以通过 JS 将 .blue 的颜色更改为所选颜色。显然,您必须记住用户的选择并在准备好文档时执行处理该选择的 JS 函数。这种解决方法当然有它的缺点(例如,通过父母定义颜色将意味着大量额外的类/父元素,否则样式化不需要这些),所以它也不是一个完全快速的方法,但它不依赖于生成多个 CSS 文件。

    在我看来,最好使用 SCSS 变量并生成多个 CSS 文件,以防您有预定义的颜色主题。如果您允许用户完全修改他们的颜色主题,我会将这些值提交到服务器并生成适当的 CSS 文件,然后将该 CSS 文件获取给用户。但是,遵循此原则,CSS 文件不会在您更改 CSS 并部署这些更改时更新。所以这种方法也有它的缺点。

    在所有相关浏览器都正确支持原生 CSS 变量之前,我担心没有完美的解决方案。

    【讨论】:

    • 这似乎是一种很棒的技术,可以让不同的网站“主题”改变整个网站的配色方案。但是,如果您想单独设置同一站点的各种元素的样式(即某种基于内容对部分进行颜色编码的 Web 应用程序),这将不起作用...
    • @Askaga,你的意思是基于用户输入?如果您的意思是基于您控制的某些东西(例如在网站开发人员中),那么它可以被实施。您只需向该部分添加另一个或不同的类,并在 SCSS 中为其使用不同的颜色变量。当然,所有颜色变量都应该出现在所有颜色变量 SCSS 文件中(例如,不能只在 2/3 的颜色变量文件中定义 $black,必须全部定义,否则会得到无效的 CSS 属性输出)
    • 实际上我的主要动机是只需要定义一次颜色改变类(.red、.green、.blue),而不是必须定义它们 n 次(每个类一次它可能被组合和)。所以我可以在一个页面上有多个部分,每个部分都有不同的配色方案。对于类似应用程序的页面来说,这可能是一个不错的功能,即仪表板,其中每个部分及其链接、按钮、选项卡都以不同的颜色进行颜色编码
    • @Askaga 我明白了。为此,您必须编写可能需要的几条规则(例如,红色边框规则、蓝色边框规则、绿色文本规则、黄色背景规则等),然后应用多个类来设置一个部分的样式(例如 class="red-border blue-text Purple-background")。就个人而言,我很少定义这样的“通用”类,并且更喜欢根据需要为每个部分设置样式,同时使用 SCSS 变量,以便如果需要更改某些内容(例如不同的绿色阴影),您只需要这样做一次,到处都会改变
    【解决方案2】:

    在 scss 中尝试了不同的策略后,我找到了以下使用 mixins 的解决方案。首先,我们必须将所有颜色及其所需的类名定义为一个列表变量:

    // define all colors
    $colors: (red, #f44), 
             (green, #3c1), 
             (blue, #78f);
    
    // define default color to be blue
    $color: nth(nth($colors, 3), 2);
    

    然后我们定义一个 mixin colorize,它首先使用默认的 $color 定义给定属性,然后迭代 $colors 列表,对每个颜色类执行相同的操作,使用父选择器:

    @mixin colorize($properties...) {
    
        // for each property assign the default $color
        @each $property in $properties {
            #{$property}: $color;
        }
    
        // for each color class - assign the class color to each property
        @each $cls, $col in $colors {
            &.#{$cls} { 
                @each $property in $properties {
                    #{$property}: $col;
                }
            }
        }
    }
    

    现在我们可以使用colorize-mixin 将特定于类的颜色分配给一个或多个css属性:

    .fillbutton { 
        @include colorize(background); 
        color: #fff; 
        padding: 0.25em 1em; 
    }
    
    .borderbutton { 
        @include colorize(border-color, color);
        background: #fff; 
        border: 1px solid; 
        padding: 0.25em 1em; 
    }
    

    最后,像这样在我们的 html 中使用它:

    <span class="fillbutton green">Green</span>
    <span class="fillbutton blue">Blue</span>
    <span class="borderbutton">Default</span>
    <span class="borderbutton green">Green</span>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-07
      • 2020-01-24
      相关资源
      最近更新 更多