使用css变量和sass实现一键主题换肤功能

需求

最近做的公共模块,需要提供给不同平台,可以通过传参实现主题色的适配,目前支持模板一键换肤以及自定义换肤

实现方案

换肤方案主要是基于CSS自定义变量以及sass动态修改data-theme实现的。

模板换肤

首先提供几套主题色模板,统一放在theme文件夹当中。

blue.scss (默认主题)

$blue: (
    // 字体
    font_color: #00a5e5,
    // 按钮背景
    background_color: #00a5e5,
    // 鼠标划过
    background_hover_color: #0094CE,
    // 禁用
    background_disable_color:#CCEDFA,
    // 边框颜色
    border_color: #00a5e5,
)
复制代码

your.scss (你的主题)

$ucode-website: (
    // 字体
    font_color: #7284fb,
    // 按钮背景
    background_color: #7284fb,
    // 鼠标划过
    background_hover_color: #6676E1,
    // 禁用
    background_disable_color: #E6EAFF,
    // 边框颜色
    border_color: #7284fb,
)
复制代码

adapt-theme.scss (主题适配器)

@import './theme.scss';
@import './themes/default.scss';

// 遍历主题
@mixin themeify {
  @each $theme-name, $theme-map in $themes {
    // !global 把局部变量强升为全局变量
    $theme-map: $theme-map !global;
    [data-theme="#{$theme-name}"] & {
        @content;
    }
  }
}

// 根据Key值获取颜色
@function themed($key) {
    @return map-get($theme-map, $key);
}

// 获取字体颜色
@mixin font_color($color) {
    @include themeify{
        color: themed($color);
    }
}

// 获取边框颜色
@mixin border_color($color) {
    @include themeify{
        border-color: themed($color);
    }
}

// 获取背景颜色
@mixin background_color($color) {
    @include themeify{
        background-color: themed($color);
    }
}

// 鼠标划过
@mixin background_hover_color($color) {
    @include themeify{
        background-color: themed($color);
    }
}

// 禁用
@mixin background_disable_color($color) {
    @include themeify{
        background-color: themed($color);
    }
}



复制代码

调用主题模板

第三方调用时传主题参数到公共模块,写入顶层元素的data-theme即可自动适配模板。

<div data-theme={this.context.theme}></div>
复制代码

适配公共组件

@import "../../../styles/adapt-theme.scss";
button {
    @include background_color("background_color");
}
复制代码

自定义颜色换肤

定义初始CSS变量,挂载在根元素,可以全局使用。

:root {
    --fontColor: initial; // 此处注意,initial才为空值
    --backgroundColor: initial;
    --backgroundHoverColor: initial;
    --backgroundDisableColor: initial;
    --borderColor: initial;
}
复制代码

第三方调用传参后,JS动态修改CSS变量。

const body = document.getElementsByTagName('body')[0];
const { themeStyles } = this.context;
for (const style in themeStyles) {
     if (themeStyles[style]) {
          body.style.setProperty(`--${style}`, themeStyles[style]);
     }
}
复制代码

最后修改主题适配器,利用CSS无效变量,可以实现自定义变量覆盖模板,当没有自定义变量时,又不会影响模板渲染。这个是关键。

// 获取字体颜色
@mixin font_color($color) {
    @include themeify{
        color: var(--fontColor, themed($color));
    }
}
复制代码
分类:
前端