【问题标题】:How to implement switchable themes in scss?如何在 scss 中实现可切换主题?
【发布时间】:2021-01-31 01:33:14
【问题描述】:

我有一个带有使用语义变量的 scss 文件的现有项目:

$background-color: white;

body {
    background-color: $background-color;
}

我想在正文中添加主题类时将背景更改为黑色:

<body class="theme-dark">...</body>

如果我删除课程(或切换到主题灯),则返回白色。

我还没有在 scss 中找到任何轻量级的方法来做到这一点(为每个主题参数化一个类似乎是一种很难维护的方法)。

我找到了一个混合 scss/css-custom 属性的解决方案:

原文:

.theme-light {
    --background-color: white;
}

更新(基于 Amar 的回答):

:root {
    --background-color: white;
}
.theme-dark {
    --background-color: black;
}

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

将 scss 变量定义为具有 css 变量扩展作为值,即(从上面):

$background-color: var(--background-color);

生成以下css:

:root { --background-color: white; }
.theme-dark { --background-color: black; }
body { background-color: var(--background-color); }

这似乎是我们想要的......?

我喜欢它,因为它只需要更改 $background-color 的定义(不是非常大的 scss 文件中的所有用法),但我不确定这是否是一个合理的解决方案?我对 scss 很陌生,所以也许我错过了一些功能..?

【问题讨论】:

  • 这将一直有效,直到您决定说 darken($background-color, 10%);
  • @YuryTarabanko 啊.. 我知道一定有什么:-/
  • 我认为您可以使用 RGB 数字代替颜色名称,这将解决此问题

标签: css sass


【解决方案1】:

可以使用 SCSS 执行此操作,但您必须为所有要设置主题的元素添加样式。这是因为 SCSS 是在构建时编译的,您不能使用类切换变量。一个例子是:

$background-color-white: white;
$background-color-black: white;

body {
  background-color: $background-color-white;
}

.something-else {
  background-color: $background-color-white;
}

// Dark theme
body.theme-dark {
  background-color: $background-color-black;

  .something-else {
    background-color: $background-color-black;
  }
}

目前最好的方法是使用 CSS 变量。您可以像这样定义默认变量:

:root {
  --background-color: white;
  --text-color: black;
}

.theme-dark {
  --background-color: black;
  --text-color: white;
}

然后,您可以像这样在元素中使用这些变量:

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

如果body 元素具有theme-dark 类,它将使用为该类定义的变量。否则,它将使用默认的根变量。

【讨论】:

  • 您是否建议不要定义和使用$background-color scss 变量?
  • @thebjorn 我刚刚更新了我的答案,以展示如何使用 SCSS 完成此操作的示例。对于主题,我会推荐 SCSS 变量,因为您可以随时切换它们,而无需为主题自定义的所有元素设置样式。
  • @thebjorn 取决于browser support,CSS 变量可能不适合您。
  • @hungerstar 幸好这​​不是问题(是的,我知道我很幸运 ;-)
  • @AmarSyla 我刚刚更新了问题,详细说明了如何将 css-variables 作为 scss 变量的值编译到答案中的最后一个代码块中。我在第一条评论中的问题是,您是否建议不要以这种方式混合 css 变量和 scss 变量?
【解决方案2】:

所有功劳归于 Dmitry Borody

我会推荐一种类似于this Medium article 中提到的方法。使用这种方法,您可以指定需要设置主题的类,而无需特别提及主题名称,因此可以一次应用多个主题。

首先,您设置一个包含主题的 SASS 地图。键可以是任何对您有意义的键,只要确保每个主题对同一事物使用相同的名称即可。

$themes: (
  light: (
    backgroundColor: #fff,
    textColor: #408bbd,
    buttonTextColor: #408bbd,
    buttonTextTransform: none,
    buttonTextHoverColor: #61b0e7,
    buttonColor: #fff,
    buttonBorder: 2px solid #fff,
  ),
  dark: (
    backgroundColor: #222,
    textColor: #ddd,
    buttonTextColor: #aaa,
    buttonTextTransform: uppercase,
    buttonTextHoverColor: #ddd,
    buttonColor: #333,
    buttonBorder: 1px solid #aaa,
  ),
);

然后使用mixinfunction 对添加主题支持。

body {
  background-color: white;
  @include themify {
    background-color: theme( 'backgroundColor' );
  }
}

.button {
  background-color: lightgray;
  color: black;

  @include themify {
    background-color: theme( 'buttonBackgrounColor' );
    color: theme( 'buttonTextColor' );
  }

  &:focus,
  &:hover {
    background-color: gray;
    
    @include themify {
      background-color: theme( 'buttonBackgroundHoverColor' );
      color: theme( 'buttonTextHoverColor' );
    }
  }
}

如果您要添加很多主题,或者一个主题会涉及很多内容,您可能需要稍微不同地设置 SCSS 文件,这样所有主题都不会使您的主 CSS 膨胀文件(就像上面的例子一样)。一种方法可能是创建一个themes.scss 文件并复制任何需要主题化的选择器路径,并使用第二个构建脚本仅输出themes.scss 文件。

混音

@mixin themify( $themes: $themes ) {
  @each $theme, $map in $themes {

    .theme-#{$theme} & {
      $theme-map: () !global;
      @each $key, $submap in $map {
        $value: map-get(map-get($themes, $theme), '#{$key}');
        $theme-map: map-merge($theme-map, ($key: $value)) !global;
      }

      @content;
      $theme-map: null !global;
    }

  }
}

函数

@function themed( $key ) {
  @return map-get( $theme-map, $key );
}

【讨论】:

  • 这确实令人印象深刻 :-) 不过我不确定我是否称它为轻量级,而且它需要更改现有(并且非常大)scss 文件中的几乎所有规则...跨度>
  • 你为什么要改变你的规则(假设你的意思是 CSS 选择器)?您只需在需要添加主题样式的地方添加@include themify {} 并将themed 函数与属性值一起使用。 @AmarSyla 的 SCSS 解决方案将需要相同的工作量,而 CSS 变量解决方案将是最精简的,但我可以看到可能不希望 --background-color 的所有实例切换的地方。在这种情况下,您将处理更多的变量并具有与 SCSS 解决方案类似的开销。如果一个小函数和一个小mixin都不是轻量级的,那我不知道该告诉你什么了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 2011-05-22
  • 2019-06-29
  • 2015-09-28
  • 1970-01-01
  • 2021-04-26
相关资源
最近更新 更多