相关文章推荐
重感情的番茄  ·  【Bug】Failed to write ...·  1 年前    · 
千杯不醉的紫菜  ·  Automating the ...·  1 年前    · 
--color-primary-extralight: #d3eafd; --color-primary-light: #b2dafb; --color-primary-medium: #6ebbf7; --color-primary: #2196f3; --color-primary-dark: #27415b;
// windi.config.js
export default defineConfig({
  theme: {
    extend: {
      colors: {
        primary: {
          extralight: 'var(--color-primary-extralight)',
          light: 'var(--color-primary-light)',
          medium: 'var(--color-primary-medium)',
          DEFAULT: 'var(--color-primary)',
          dark: 'var(--color-primary-dark)',

这样就能够基本实现在 WindiCSS 中使用 CSS 变量了,不过还有一个小问题:

WindiCSS 支持为颜色设置透明度,例如 bg-gray-800/80 bg-gray-800 bg-opacity-80 这两种写法。上面的配置方式会导致这种语法失效(丢失透明度)。所以,我们需要给CSS变量换一种形式。同时,需要一个高阶工具函数来包装一下变量:

:root {
  --color-primary-extralight: 211 234 253;
  --color-primary-light: 178 218 251;
  --color-primary-medium: 110 187 247;
  --color-primary: 33 150 243;
  --color-primary-dark: 39 65 91;
// windi.config.js
function withOpacityValue(variable) {
  return val => {
    if (val.opacityValue === undefined) {
      return `rgb(var(${variable}))`
    return `rgb(var(${variable}) / ${val.opacityValue})`
export default defineConfig({
  theme: {
    extend: {
      colors: {
        primary: {
          extralight: withOpacityValue('--color-primary-extralight'),
          light: withOpacityValue('--color-primary-light'),
          medium: withOpacityValue('--color-primary-medium'),
          DEFAULT: withOpacityValue('--color-primary'),
          dark: withOpacityValue('--color-primary-dark'),

如此一来,每当使用 primary 颜色时,WindiCSS 都会调用函数来生成样式,通过对 opacityValue 的判断来实现对透明度语法的支持。

SCSS 生成 CSS 变量

显然,如果手动为 light extralight 等颜色变种指定颜色值是不现实的,况且现在需要用 R G B 三个数字来表示颜色,编辑器没有高亮,不直观,也会导致维护困难。

这时候SCSS就能派上用场了!SCSS提供了基础的CSS数据类型,判断、遍历语法,同时也提供了海量的工具函数(例如 red() blue() green()等用于通道分离,mix()用于颜色混合)

首先来实现一个工具函数,将传入的十六进制颜色转换成 R G B 三个数字的形式

@function getColorValue($color) {
  @return #{red($color)} #{green($color)} #{blue($color)};
/* getColorValue(#2196f3) -> 33 150 243 */

我预想中的情况是——只要给一个 primary 的基础色,SCSS就能帮我把 light extralight 等颜色变种都生成出来。我是用 mix 方法来实现:

@mixin spread-theme-map($map: ()) {
  @each $key, $value in $map {
    #{"--"+$key}: $value;
@function theme-primary-map($primary-color: #2196f3) {
  @return (
    color-primary-dark: getColorValue(mix($primary-color, black, 30%)),
    color-primary: getColorValue($primary-color),
    color-primary-medium: getColorValue(mix($primary-color, white, 70%)),
    color-primary-light: getColorValue(mix($primary-color, white, 35%)),
    color-primary-extralight: getColorValue(mix($primary-color, white, 15%))
/* spread-theme-map(theme-primary-map(#2196f3)) */

这样,就能针对某一个颜色生成对应的系列颜色属性了。接下来,只需要定义一个数组,把需要的主题色放进去,跑个循环即可(从 Material Design 的文档里随便挑了几个养眼的颜色):

$themeColorList: (
  #2196f3,
  #f44336,
  #9c27b0,
  #4caf50,
  #3f51b5,
  #795548,
  #607d8b,
  #009688
@for $i from 1 through length($themeColorList) {
  $color: nth($themeColorList, $i);
  .theme-#{$i} {
    @include spread-theme-map(theme-primary-map($color));

在VSCode中,看起来是这样的:

const randomThemeColorIndex = useState('randomThemeColorIndex', () =>
  Math.floor(Math.random() * themeColorList.length) + 1
useHead({
  bodyAttrs: {
    class: 'theme-' + randomThemeColorIndex.value,
 分享到 Twitter
                 # # # #                
首页      代码      SCSS+WindiCSS实现主题色切换

戴兜

文章作者

发表回复 取消回复

textsms