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)
不过该实现有点毛糙,存在几个小问题:
- 每个须要利用主题款式的 CSS 选择器中,都要写一遍对应主题须要的款式,比拟繁琐
- 如果有多个主题,代码量会极具减少,并且很多都是反复的“模板代码”
针对这些问题,咱们能够利用 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 实现主题切换还有很多能够优化的点。这里轻易列两条常见的:
-
如果有多条主题款式须要利用,每一条都要写一遍
@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 ) ); }
-
如果还须要应用
!important
去笼罩一些因为权重问题无奈利用的款式(比方应用了内部 UI 库,内部 UI 库中应用了!important
,须要笼罩该款式),怎么解决?// 这里提供一个思路,能够增加一个参数 $important @mixin themify($key, $valueMap: null, $important: false) {// xxx}