LESS / SASS中的主题变量

问题描述 投票:3回答:1

我希望在我的应用程序中支持多个主题 - 此外,我希望能够通过更改body元素上的类来动态更改主题,或者甚至让应用程序的不同部分使用不同的主题。

在我之前的项目中,每次我需要使用特定于主题的变量时,我都会通过添加显式规则来实现:

.theme-light & { background-color: @theme-light-background; }
.theme-dark & { background-color: @theme-dark-background; }

但是,这种方法不能很好地扩展,并且会给源文件增加不必要的膨胀。

现在,我正在寻找一种更加自动化的方法。即下列

.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都不能以自然的方式做到这一点。似乎将它作为单独的后处理器实现并不太困难,它为每个主题构建样式表,然后比较它们并将差异范围限定在相应的“名称空间”中。我怀疑这样的事情可能已经存在,但我找不到任何东西。

有什么建议?

css sass less
1个回答
6
投票

不确定Less,但在Sass中,通过将主题信息存储到地图中并使用使用@content将内容块传递到mixins的功能,可以相对容易地实现它。以下是它的外观示例,非常快速的解决方案,但您可以得到一个想法:

// 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玩这个片段。

© www.soinside.com 2019 - 2024. All rights reserved.