带有动态变量的 SCSS 主题
Posted
技术标签:
【中文标题】带有动态变量的 SCSS 主题【英文标题】:SCSS Theming with Dynamic Variables 【发布时间】:2020-01-08 22:25:26 【问题描述】:大家好!
我目前正在开发 CSS 框架的主题功能,遇到了一些问题,希望您能提供帮助。
我创建了一个名为$themes
的 SASS 地图,其中包含不同主题的颜色。我从一篇中等文章(谁没有)中复制粘贴了一些代码,然后我的主题作品就大功告成了!
但是...
这个:
@include themify($themes)
.btn
color: themed('blue');
打开。每一个。零件。比我认为在我将要做的大量样式中可维护的代码更草率。所以...
我的目标
我想做一些超级 hacky 和很棒的事情:
@include themify($themes)
$blue: themed(blue);
我想对变量进行主题化,所以我所要做的就是添加 $blue
而不是很多调用 mixins 和不必要的胡言乱语。
如果我能得到这样的东西,它会看起来像这样:
.btn
background: $blue;
所有主题都将事先处理好!
但当然它从来没有那么容易,因为它不起作用......如果你们中的一个很棒的sass
魔术师可以用这个来发挥一些魔法,那将是天赐之物,我会将你包含在很棒的贡献者的源代码中。
代码
$themes
sass-map:
$themes: (
light: (
'blue': #0079FF
),
dark: (
'blue': #0A84FF
)
);
来自这个很棒的Medium Article的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);
对于如何实现这一点的任何建议都将 100% 感激。非常感谢您将您作为出色的贡献者添加到源代码中。 提前致谢!
【问题讨论】:
【参考方案1】:Sass 不允许您动态创建变量——为什么您需要在全局范围内手动声明变量。
$themes: (
light: (
'text': dodgerblue,
'back': whitesmoke
),
dark: (
'text': white,
'back': darkviolet
)
);
@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);
@mixin themed
@include themify($themes)
$text: themed('text') !global;
$back: themed('back') !global;
@content;
@include themed
div
background: $back;
color: $text;
border: 1px solid;
这种方法的问题(除了维护繁琐之外)是它会用与主题无关的东西使你的 CSS 膨胀——在上面的例子中,边框将被重复。
.theme-light div
background: whitesmoke;
color: dodgerblue;
border: 1px solid; // <=
.theme-dark div
background: darkviolet;
color: white;
border: 1px solid; // <=
虽然我认为可以创建一个设置,将每个主题的范围限定为它自己的单独样式表(例如 light.css 和 dark.css),但我认为您应该考虑使用 CSS variables 来处理这个
$themes: (
light: (
'text': dodgerblue,
'back': whitesmoke
),
dark: (
'text': white,
'back': darkviolet
)
);
@each $name, $map in $themes
.theme-#$name
@each $key, $value in $map
--#$key: #$value;
div
background: var(--back);
color: var(--text);
border: 1px solid;
CSS 输出
.theme-light
--text: dodgerblue;
--back: whitesmoke;
.theme-dark
--text: white;
--back: darkviolet;
div
background: var(--back);
color: var(--text);
border: 1px solid;
注意!您只需要将主题类添加到例如body 标签和嵌套元素将继承这些值:)
【讨论】:
动态创建变量是什么意思? 假设您有一个映射$map:( foo: 1, bar: 2 )
,您将无法遍历键并创建 $foo: 1;
和 $bar: 2;
- 您必须像 $foo: map-get($map, foo);
一样手动创建它们【参考方案2】:
我会使用这种方法(它看起来有点简单):
$themes-names: (
primary: (
background: $white,
color: $dark-grey,
font-size: 18px,
),
dark: (
background: $dark,
font-size: 10px,
)
);
$primaryName: "primary";
$darkName: "dark";
@function map-deep-get($map, $keys...)
@each $key in $keys
$map: map-get($map, $key);
@return $map;
@mixin print($declarations)
@each $property, $value in $declarations
#$property: $value
@mixin wrappedTheme($declarations)
@each $theme, $value in $declarations
$selector: "&.theme-#$theme";
#$selector
@include print(map-deep-get($themes-names, $theme));
$color-default: map-deep-get($themes-names, "primary", "color");
.button-themed
/*extend some shared styles*/
@extend %button;
/* generate &.theme-primary... and &.theme-dark... */
@include wrappedTheme($themes-names);
/*override*/
&.theme-#$darkName
border: 5px solid $color-default;
color: $white;
/* can override/extend specific theme --modifier */
&.theme-#$primaryName--modifier
@include print(map-deep-get($themes-names, $primaryName));
/* will add all from: $themes-names[$primaryName]
/---
background: $white,
color: $dark-grey,
font-size: 18px,
*/
font-size: 22px;
color: $color-default;
【讨论】:
以上是关于带有动态变量的 SCSS 主题的主要内容,如果未能解决你的问题,请参考以下文章