Sass利用之实现主题切换

背景

实现主题切换有几种不同的计划,比方应用CSS变量,应用JavaScript动静加载对应的主题款式文件等。本文次要讲的是如何应用Sass实现主题切换。

前置常识

理解Sass的根本应用

  • variable
  • mixin
  • map

实质

Sass作为CSS预处理器,须要编译成CSS后,能力被浏览器辨认和解析。因而无奈在浏览器中间接应用Sass实现相似CSS变量那种动静切换。实质上来说,我的项目中有几个主题就要提前定义好几份主题款式并全副引入。

思路

首先,咱们须要给利用的顶层元素增加一个主题标识,用于标识以后的主题,用于之后利用上对应的主题款式。该标识能够是数据属性,也能够是类,也能够是id,这里采纳数据属性。

<html>  <div class="app" data-theme="light"></div></html>

而后,每次切换主题时,通过更新该标识,页面就会利用款式文件中提前定义好的对应的主题款式。

.app {  &[data-theme='light'] {    color: #333;  }    &[data-theme='dark'] {    color: #fff;  }}

实现

根底版

基于主题切换的实质和思路,咱们能够通过硬编码,实现一个简略的主题切换。

<div id="app" class="app">  <h1 class="title">Hello, World</h1>  <p class="subtitle">以后主题:<span id="theme-current">亮色</span></p>  <button class="theme-switch light" data-theme="light">亮色</button>  <button class="theme-switch dark" data-theme="dark">暗色</button></div>

首先给利用增加一个主题标识,这里我通过给body元素增加一个数据属性data-theme示意以后的主题。默认为light

<body data-theme="light">  <div class="app"></div></body>

而后提前定义好所有主题款式:

// 所有主题款式$bg-color-light: #ffffff;$bg-color-dark: #091a28;$title-color-light: #363636;$title-color-dark: #ffffff;$subtitle-color-light: #4a4a4a;$subtitle-color-dark: cyan;.app {  // 默认主题款式(light主题)  background-color: $bg-color-light;    // dark主题  [theme='dark'] & {    background-color: $bg-color-dark;  }}.title {  color: $title-color-light;    [theme='dark'] & {    color: $title-color-dark;  }}.subtitle {  color: $subtitle-color-light;    [theme='dark'] & {    color: $subtitle-color-dark;  }}

最初,当咱们点击不同主题按钮时,就会更新body上的主题标识data-theme,这样,款式文件中对应的主题款式就会被利用上了。

残缺代码和实现成果能够参考Codepen:


SASS实现主题换肤/主题切换-根底版 by zhouqichao (@Tom_chao)

不过该实现有点毛糙,存在几个小问题:

  1. 每个须要利用主题款式的CSS选择器中,都要写一遍对应主题须要的款式,比拟繁琐
  2. 如果有多个主题,代码量会极具减少,并且很多都是反复的“模板代码”

针对这些问题,咱们能够利用Sass的一些个性实现一个进阶版的主题切换。

进阶版

首先,针对根底版暴露出的问题。咱们须要对Sass变量做一点小小的调整。这里咱们将主题款式封装成了map格局,map中每一个元素都对应着不同主题下的款式。

// 所有主题款式$bg-color: (  // 亮色  light: #fff,  // 暗色  dark: #091a28);$title-color: (  light: #363636,  dark: #ffffff);$subtitle-color: (  light: #4a4a4a,  dark: cyan);

针对反复的模版代码和代码繁琐的问题,Sass中有个个性mixin,正好能够利用上。

接下来,咱们要封装一个mixin,专门解决根底版1-手写代码的繁琐的问题。

这里应用了Sass中的插值表白#{}map-get办法,#{}相似于JavaScript中的计算属性,能够动静设置属性名,map-get办法用于从map中获取某一个属性对应的值。

@mixin themify($key, $valueMap) {  // 默认主题  #{$key}: map-get($valueMap, 'light');      // dark主题  [theme='dark'] & {    #{$key}: map-get($valueMap, 'dark');  }}

themify次要封装了默认主题款式light,和dark主题款式,这样咱们在选择器里,只须要include这些款式即可。

.app {  @include themify('background-color', $bg-color);}.title {  @include themify('color', $title-color);}.subtitle {  @include themify('color', $subtitle-color);}

当初看这些代码是不是简洁多了?省去了本人手写那些繁琐的模板代码!

针对“多主题模版代码会更多”的问题,解决起来也就很容易了。只须要简略批改下该mixin,增加上对应的主题款式即可。

@mixin themify($key, $valueMap) {  // light主题  #{$key}: map-get($valueMap, 'light');      // dark主题  [theme='dark'] & {    #{$key}: map-get($valueMap, 'dark');  }    // dark1主题  [theme='dark1'] & {    #{$key}: map-get($valueMap, 'dark1');  }    // dark2主题  [theme='dark2'] & {    #{$key}: map-get($valueMap, 'dark2');  }}

当然,咱们还能够对mixin做一下优化,能够将主题封装成list格局,而后通过遍历主题,简化mixin:

@mixin themify($key, $valueMap) {  // theme list  $themes: light, dark;    @each $theme in $themes {    [theme=#{$theme}] & {      #{$key}: map-get($valueMap, $theme);    }  }}

这样看起来就清新多了。
残缺代码和实现成果能够参考Codepen:

SASS实现主题换肤/主题切换-进阶版 by zhouqichao (@Tom_chao)

总结

Sass作为一款风行的CSS预处理器,提供了插值表白#{}map类型等个性,在实现主题切换方面提供了不少便当。

当然,Sass实现主题切换还有很多能够优化的点。这里轻易列两条常见的:

  1. 如果有多条主题款式须要利用,每一条都要写一遍@include,感觉有点麻烦,能不能只写一遍@include

    .app {  @include themify('background-color', $bg-color);  @include themify('color', $text-color);  // ...}// 心愿能够只写一遍@include.app {  @include themify(    (    'background-color': $bg-color,    'color': $text-color    )  );}
  2. 如果还须要应用!important去笼罩一些因为权重问题无奈利用的款式(比方应用了内部UI库,内部UI库中应用了!important,须要笼罩该款式),怎么解决?

    // 这里提供一个思路,能够增加一个参数$important@mixin themify($key, $valueMap: null, $important: false) {    // xxx}