如何在scss中实现可切换的主题?

kmbjn2e3  于 2023-11-19  发布在  其他
关注(0)|答案(3)|浏览(159)

我有一个现有的项目,其中包含一个使用语义变量的scss文件:

$background-color: white;

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

字符串
当我向主体添加主题类时,我想将背景更改为黑色:

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


如果我移除类(或切换到主题灯),则返回白色。
我还没有在scss中找到任何轻量级的方法来实现这一点(为每个主题参数化一个类似乎是一种很难维护的方法)。
我发现了一个混合的scss/css自定义属性解决方案:

原文:

.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-variable扩展作为值,即(从上面开始):

$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很陌生,所以也许我错过了一些功能。

y53ybaqx

y53ybaqx1#

使用SCSS可以做到这一点,但你必须为所有想要主题化的元素添加样式。这是因为SCSS是在构建时编译的,你不能用类切换变量。一个例子是:

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

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类,它将使用为该类定义的变量。否则,它将使用默认的根变量。

0md85ypi

0md85ypi2#

所有的功劳都要归功于德米特里·博罗迪
我推荐一种类似于this Medium article中提到的方法。使用这种方法,您可以指定需要主题化的类,而无需特别提及主题名称,因此可以同时应用多个主题。
首先,你建立一个包含你的主题的SASSMap。键可以是任何对你有意义的东西,只要确保每个主题都使用相同的名字来做同样的事情。

$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酒店

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

pgpifvop

pgpifvop3#

添加class=“theme-light”到任何根标签。例如,这里我们将切换当前主题,将class从“theme-light”替换为“theme-dark”。

<html class="theme-light">

字符串
当然,“light”和“dark”你可以用你的主题名称替换。
现在我们需要添加两个scss文件。首先,
themes.scss

$themes: (
  light: (
    primary: #fff,
  ),
  dark: (
    primary: #212121,
  ),
);


其次,
themed-style.scss

@import './themes';

@mixin themed-style($key, $color) {
  @each $theme-name, $theme-color in $themes {
    :global(.theme-#{$theme-name}) & {
      #{$key}: map-get(map-get($themes, $theme-name), $color);
    }
  }
}


最后,使用它

@import './themed-style';

.root {
  @include themed-style('background', 'primary');
}

相关问题