CSS 个变量,适用于旧版浏览器

CSS variables with fallback for older browsers

TL;DR:如何使用 SCSS 让 CSS 变量具有旧浏览器的回退。

我正在尝试理解这个 article。在我看来,您必须已经是高级 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... */
}

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

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

既然你已经有了地图,你所需要的就是通过提供密钥来获取值 'primary'

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

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

@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

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

更新: Postcss Custom properties 可以回退并且比下面的代码更容易

第 1 步:声明 scss 个变量

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

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

第 2 步:自动化 css 4 变量生成

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

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

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

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

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

注意前缀(--colors-)与上面的scss色图同名。为什么会在最后一步变得清楚。


第 3 步:大量地图!

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

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

这里我们添加映射 $props,它将 css 属性 映射到包含值的映射。 background-color 会保留颜色,所以正确的贴图是 $colors.

map-maps 是 props 的副本,其中我们使用所述地图的名称而不是地图。 (这与步骤 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 的变量,我们将 $props 映射内部的值分配给键 background-color 处的值,而键 $colors 恰好是 $colors 映射.这有点迷宫,但一旦你解决了它就没那么复杂了。

然后备用:

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

这只是在 $var 键(恰好是主键)处获取我们刚刚获得的映射(即 $colors)的值。因此结果是 #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);
}

现在这是对文章中所做内容的简化。您应该检查它以使代码更健壮。

如果您正在使用 Sass,您可以通过 Sass 混入自动回退。创建一个 CSS 变量名称及其值的映射,然后您可以在输出后备样式和首选样式的混合中查找这些值

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

Et voilà :)