具有动态变量的 SCSS 主题

jos*_*ett 8 html css themes sass scss-mixins

大家好!

我目前正在开发 CSS 框架的主题功能,并遇到了一些问题,希望您能够帮助解决。


我创建了一个名为 的 SASS 地图$themes,其中包含不同主题的颜色。我从一篇中等文章中复制粘贴了一些代码(谁没有),然后我的主题就成功了! 但是
这个:

@include themify($themes) {
    .btn {
        color: themed('blue');
    }
}
Run Code Online (Sandbox Code Playgroud)

在。每一个。成分。是比我认为在我将要做的大量样式中可维护的代码更草率的代码。
所以...

我的目标


我想做一些超级黑客和很棒的事情,如下所示:

@include themify($themes) {
    $blue: themed(blue);
}
Run Code Online (Sandbox Code Playgroud)

我想对变量进行主题化,所以我所要做的就是添加$blue而不是大量调用混合和不必要的胡言乱语。
如果我能让这样的东西发挥作用,它看起来会像这样:

.btn {
    background: $blue;
}
Run Code Online (Sandbox Code Playgroud)

所有的主题都会事先处理好!
但当然,这从来都不是那么容易,因为它不起作用......如果你们中的一位出色的sass魔术师能够用这个来施展一些魔法,那将是天赐之物,我会将您包含在出色的贡献者的源代码中。

代码


sass$themes地图:

$themes: (
    light: (
        'blue': #0079FF
    ),
    dark: (
        'blue': #0A84FF
    )
);
Run Code Online (Sandbox Code Playgroud)

来自这篇很棒的Medium 文章的copypasta mixin :

@mixin themify($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);
}
Run Code Online (Sandbox Code Playgroud)

任何有关如何实现这一目标的建议将 100% 受到赞赏。非常感谢您将您作为出色的贡献者添加到源代码中。

提前致谢!

Jak*_*b E 10

Sass 不允许您动态创建变量 \xe2\x80\x93 为什么您需要在全局范围内手动声明变量。

\n
$themes: (\n    light: (\n        \'text\': dodgerblue,\n        \'back\': whitesmoke \n    ),\n    dark: (\n        \'text\': white,\n        \'back\': darkviolet\n    )\n);\n\n\n@mixin themify($themes) {\n  @each $theme, $map in $themes {\n    .theme-#{$theme} {\n      $theme-map: () !global;\n      @each $key, $submap in $map {\n        $value: map-get(map-get($themes, $theme), \'#{$key}\');\n        $theme-map: map-merge($theme-map, ($key: $value)) !global;\n      }\n      @content;\n      $theme-map: null !global;\n    }\n  }\n}\n\n@function themed($key) {\n  @return map-get($theme-map, $key);\n}\n\n@mixin themed {\n    @include themify($themes){\n        $text: themed(\'text\') !global;\n        $back: themed(\'back\') !global;      \n        @content;\n    }\n}\n\n@include themed {\n    div {\n        background: $back;\n        color: $text; \n        border: 1px solid; \n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这种方法的问题(除了维护起来很繁琐之外)是,它会因为与上面示例中的主题 \xe2\x80\x93 无关的内容而使 CSS 膨胀,边框将被重复。

\n
.theme-light div {\n  background: whitesmoke;\n  color: dodgerblue;\n  border: 1px solid; //  <= \n}\n\n.theme-dark div {\n  background: darkviolet;\n  color: white;\n  border: 1px solid; // <=\n}\n
Run Code Online (Sandbox Code Playgroud)\n

虽然我认为可以创建一个设置,将每个主题范围限定为它自己的单独样式表(例如 light.css 和 dark.css),但我认为您应该考虑使用CSS 变量来处理这个问题

\n
$themes: (\n    light: (\n        \'text\': dodgerblue,\n        \'back\': whitesmoke \n    ),\n    dark: (\n        \'text\': white,\n        \'back\': darkviolet\n    )\n);\n\n@each $name, $map in $themes {\n    .theme-#{$name} {\n        @each $key, $value in $map {\n            --#{$key}: #{$value};\n        }\n    }\n} \n\ndiv {\n    background: var(--back);\n    color: var(--text); \n    border: 1px solid;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

CSS输出

\n
.theme-light {\n  --text: dodgerblue;\n  --back: whitesmoke;\n}\n\n.theme-dark {\n  --text: white;\n  --back: darkviolet;\n}\n\ndiv {\n  background: var(--back);\n  color: var(--text);\n  border: 1px solid;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

笔记!您只需将主题类添加到例如 body 标记中,嵌套元素将继承这些值:)

\n