【问题标题】:SCSS Theming with Dynamic Variables带有动态变量的 SCSS 主题
【发布时间】: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% 感激。非常感谢您将您作为出色的贡献者添加到源代码中。

提前致谢!

【问题讨论】:

    标签: html css sass themes scss-mixins


    【解决方案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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-11
      • 2018-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-25
      • 2020-06-22
      相关资源
      最近更新 更多