21

TL;DR:如何使用 SCSS 为旧版浏览器提供具有后备功能的 CSS 变量。

我试图理解这篇文章。在我看来,你必须已经是高级 SASS 用户才能理解它,而我不是。更糟糕的是,这是我在这个主题上找到的唯一一篇文章。

这是我想要实现的目标:

我的scss应该是:

body {
  @include v(background-color, primary)
}

那么处理后的CSS应该是

body{
   background: yellow; /* Yellow being defined above as the primary color */
   background: var(--color-primary);
}

通过玩一点,我已经可以像这样得到 CSS 变量的值:

$colors: (
  primary: yellow,
);

:root {
  @each $name, $color in $colors {
    --color-#{$name}: $color;
  }
}

@mixin background-color($color_) {
  background: var(--color-#{$color_});
}

要使用它:

body{
  @include background-color(primary);
}

这将导致:

body {
    background: var(--color-primary);
    /* But the fallback is missing :(, I tried  things with the map-get but it's really eluding me... */
}
4

3 回答 3

30

如果你使用的是 Sass,你可以通过 Sass mixin 自动执行回退。创建您的 CSS 变量名称及其值的映射,然后您可以在输出回退样式和首选样式的 mixin 中查找这些值

$vars: (
  primary: yellow,
);

:root {
  --primary: map-get($vars, primary);
}

@mixin var($property, $varName) {
  #{$property}: map-get($vars, $varName);
  #{$property}: var(--#{$varName});
}

上面的 mixin 是这样使用的:

body {
  @include var(background-color, primary);
}

并输出以下 CSS:

:root {
  --primary: yellow;
}

body {
  background-color: yellow;
  background-color: var(--primary);
}

等等瞧 :)

于 2018-02-10T09:32:13.647 回答
13

更新: Postcss 自定义属性可以做回退,并且比下面的代码更容易

第 1 步:声明 scss 变量

所以首先我们想把一些变量放在 a 中$map,我将使用颜色变量:

$colors: (
  primary: #FFBB00,
  secondary: #0969A2
);

第 2 步:自动生成 css 4 var

// ripped CSS4 vars out of color map
:root {
  // each item in color map
  @each $key, $value in $colors {
    --colors-#{$key}: $value;
  }
}

在 root 中发生的是:对于颜色映射中的每个键和值,我们打印以下内容:

--colors-#{$key}: $value;

这对应于css变量声明。我相信键周围的奇怪#{}之处在于值周围没有空格。因此结果是:

--colors-primary: #FFBB00,
--colors-secondary: #0969A2

请注意,前缀 ( --colors-) 与其上方的 scss 颜色图同名。为什么会在最后一步变得清晰。


第三步:大量地图!

$props: (
  background-color: $colors
);

$map-maps: (
  background-color: colors
);

在这里,我们添加将$propscss 属性映射到包含值的映射的映射。background-color将保持颜色,所以正确的地图是$colors.

map-maps是道具的副本,而不是地图,我们有所述地图的名称。(这与步骤 2 中的注释有关)。

第4步:让它工作!

@mixin v($prop, $var) {
  // get the map from map name
  $map: map-get($props, $prop);
  // fallback value, grab the variable's value from the map
  $var-fall: map-get($map, $var);
  // our css4 variable output
  $var-output: var(--#{$map}-#{$var});    
  #{$prop}: $var-fall;
  // css4 variable output
  #{$prop}: $var-output;
}

body{
  @include v(background-color, primary);
}

我将文章中的代码简化了很多,它仍然有效,至少对于这个例子,文章中的代码考虑了更多。

无论如何,这就是发生的事情。

首先,我们调用 mixin:

  @include v(background-color, primary);

然后一进门,

 $map: map-get($props, $prop); // map-get($props, background-color)

我们有一个名为的变量,我们将映射$map内部的值分配给该键,该键恰好是映射。这有点像迷宫,但一旦你解决了它就没有那么复杂了。$propsbackground-color$colors

然后对于后备:

 $var-fall: map-get($map, $var);

这只是获取我们刚刚在键(恰好是主键$colors)处获得的映射的值(即 )。$var因此结果是#FFBB00

对于 css 变量

  $map-name: map-get($map-maps, $prop);
  $var-output: var(--#{$map-name}-#{$var});

我们重新创建了我们为在@each循环中生成 var 所做的事情


整个代码是:

$colors: (
  primary: #FFBB00,
  secondary: #0969A2
);

// ripped CSS4 vars out of color map
:root {
  // each item in color map
  @each $name, $color in $colors {
    --colors-#{$name}: $color;
  }
}



$props: (
  background-color: $colors,
  color:            $colors
);

$map-maps: (
  background-color: colors
);



@mixin v($prop, $var) {
  // get the map from map name
  $map: map-get($props, $prop);
  // fallback value, grab the variable's value from the map
  $var-fall: map-get($map, $var);
  // our css4 variable output

  $map-name: map-get($map-maps, $prop);
  $var-output: var(--#{$map-name}-#{$var});

  #{$prop}: $var-fall;
  // css4 variable output
  #{$prop}: $var-output;
}

body{
  @include v(background-color, primary);
}

现在这是对文章中所做工作的简化。您应该检查一下以使代码更加健壮。

于 2017-05-30T23:46:32.747 回答
1

我假设您知道它没有显示回退的原因。但既然这是一个答案,我会解释原因

当前的 mixin 块只有一个背景属性,这使得 sass 编译器只生成一个属性。我认为 sass 无法识别浏览器是否支持“var”。因此,我们必须明确指定是否需要回退。

既然你已经有了地图,你所需要的就是通过给出键'primary'来获取值

 @mixin background-color($color_) {
      background: var(--color-#{$color_});  
      background: map-get($colors, primary);
    }

这将始终将背景:黄色添加到正文类。或者,如果您想根据条件控制后备的添加。你可以这样做

@mixin background-color($color_, $showFall) {
  background: var(--color-#{$color_});  
  @if $showFall {
    background: map-get($colors, primary);
  }
}

像这样打电话

body{
  @include background-color(primary, true);
}

相同的代码笔 https://codepen.io/srajagop/pen/xdovON

注意:我在假设您只希望背景颜色起作用而不是该帖子中提到的所有其他属性的假设下编写答案。为此,您需要创建适当的数据结构

于 2017-05-30T22:38:10.307 回答