LESS/SASS 中的主题变量
Themed variables in LESS/SASS
我希望在我的应用程序中支持多个主题 - 此外,我希望能够动态更改主题,方法是更改 body
元素上的 class,甚至应用的不同部分使用不同的主题。
在我之前的项目中,每次我需要使用特定于主题的变量时,我都是通过添加显式规则来实现的:
.theme-light & { background-color: @theme-light-background; }
.theme-dark & { background-color: @theme-dark-background; }
但是,该方法不能很好地扩展,并且会向源文件添加不必要的膨胀。
现在,我正在为此寻找一种更加自动化的方法。 IE。以下
.button {
border-radius: 4px;
background-color: @ui-background;
color: @ui-foreground;
border: 1px solid mix(@ui-background, @ui-foreground, 50%);
}
会变成类似
的东西
.button {
border-radius: 4px;
border: 1px solid #808080;
/* normally we wouldn't expect this to appear here, but in our case
both themes have the same border color so we can't tell the difference */
}
.theme-light .button {
background-color: #fff;
color: #000;
}
.theme-dark .button {
background-color: #000;
color: #fff;
}
据我所知,LESS 和 SASS 都不能以自然的方式做到这一点。似乎将它实现为一个单独的 post 处理器并不太难,它为每个主题构建样式表,然后比较它们并将差异范围限定在相应的 "namespaces" 中。我怀疑这样的东西可能已经存在,但我找不到任何东西。
有什么建议吗?
不确定 Less,但在 Sass 中可以通过将主题信息存储到地图中并使用 @content
将内容块传递到 mixin 中来相对容易地实现它。这是它的外观示例,非常快速的解决方案,但您可以得到一个想法:
// Themes definition
// - First level keys are theme names (also used to construct theme class names)
// - Second level keys are theme settings, can be referred as theme(key)
$themes: (
light: (
background: #fff,
foreground: #000,
),
dark: (
background: #000,
foreground: #fff,
),
);
// Internal variable, just ignore
$_current-theme: null;
// Function to refer to theme setting by name
//
// @param string $name Name of the theme setting to use
// @return mixed
@function theme($name) {
@if ($_current-theme == null) {
@error "theme() function should only be used into code that is wrapped by 'theme' mixin";
}
@if (not map-has-key(map-get($themes, $_current-theme), $name)) {
@warn "Unknown theme key '#{$name}' for theme '#{$_current-theme}'";
@return null;
}
@return map-get(map-get($themes, $_current-theme), $name);
}
// Theming application mixin, themable piece of style should be wrapped by call to this mixin
@mixin theme() {
@each $theme in map-keys($themes) {
$_current-theme: $theme !global;
.theme-#{$theme} & {
@content;
}
}
$_current-theme: null !global;
}
.button {
border-radius: 4px;
@include theme() {
background-color: theme(background);
color: theme(foreground);
}
}
这段代码会给你这样的结果:
.button {
border-radius: 4px;
}
.theme-light .button {
background-color: #fff;
color: #000;
}
.theme-dark .button {
background-color: #000;
color: #fff;
}
看起来非常接近您要实现的目标。您可以在 Sassmeister.
上玩这个片段
我希望在我的应用程序中支持多个主题 - 此外,我希望能够动态更改主题,方法是更改 body
元素上的 class,甚至应用的不同部分使用不同的主题。
在我之前的项目中,每次我需要使用特定于主题的变量时,我都是通过添加显式规则来实现的:
.theme-light & { background-color: @theme-light-background; }
.theme-dark & { background-color: @theme-dark-background; }
但是,该方法不能很好地扩展,并且会向源文件添加不必要的膨胀。
现在,我正在为此寻找一种更加自动化的方法。 IE。以下
.button {
border-radius: 4px;
background-color: @ui-background;
color: @ui-foreground;
border: 1px solid mix(@ui-background, @ui-foreground, 50%);
}
会变成类似
的东西.button {
border-radius: 4px;
border: 1px solid #808080;
/* normally we wouldn't expect this to appear here, but in our case
both themes have the same border color so we can't tell the difference */
}
.theme-light .button {
background-color: #fff;
color: #000;
}
.theme-dark .button {
background-color: #000;
color: #fff;
}
据我所知,LESS 和 SASS 都不能以自然的方式做到这一点。似乎将它实现为一个单独的 post 处理器并不太难,它为每个主题构建样式表,然后比较它们并将差异范围限定在相应的 "namespaces" 中。我怀疑这样的东西可能已经存在,但我找不到任何东西。
有什么建议吗?
不确定 Less,但在 Sass 中可以通过将主题信息存储到地图中并使用 @content
将内容块传递到 mixin 中来相对容易地实现它。这是它的外观示例,非常快速的解决方案,但您可以得到一个想法:
// Themes definition
// - First level keys are theme names (also used to construct theme class names)
// - Second level keys are theme settings, can be referred as theme(key)
$themes: (
light: (
background: #fff,
foreground: #000,
),
dark: (
background: #000,
foreground: #fff,
),
);
// Internal variable, just ignore
$_current-theme: null;
// Function to refer to theme setting by name
//
// @param string $name Name of the theme setting to use
// @return mixed
@function theme($name) {
@if ($_current-theme == null) {
@error "theme() function should only be used into code that is wrapped by 'theme' mixin";
}
@if (not map-has-key(map-get($themes, $_current-theme), $name)) {
@warn "Unknown theme key '#{$name}' for theme '#{$_current-theme}'";
@return null;
}
@return map-get(map-get($themes, $_current-theme), $name);
}
// Theming application mixin, themable piece of style should be wrapped by call to this mixin
@mixin theme() {
@each $theme in map-keys($themes) {
$_current-theme: $theme !global;
.theme-#{$theme} & {
@content;
}
}
$_current-theme: null !global;
}
.button {
border-radius: 4px;
@include theme() {
background-color: theme(background);
color: theme(foreground);
}
}
这段代码会给你这样的结果:
.button {
border-radius: 4px;
}
.theme-light .button {
background-color: #fff;
color: #000;
}
.theme-dark .button {
background-color: #000;
color: #fff;
}
看起来非常接近您要实现的目标。您可以在 Sassmeister.
上玩这个片段