引言
前端换肤,旨在更换web前端应用的主题,来满足用户在不同时期的实际需求。
技术原理
前端换肤的技术原理有很多种这里给大家介绍一种,css 变量 + 主题类型。就是通过不同的类名实现相同的 css 变量,但是其 css 变量的值又是各自实现的,之后在编写组件时全部将写死的值换成对应的 css 变量即可。
实现步骤
假设我们要实现 dark 和 day 两种不同主题。
1、定义 dark 主题 theme/dark/color.less
less
@mainColor: #01305f;
@mainTextColor: #ffffff;
@mainBgColor: #012447;
//覆盖 第三方库主题色 例如 ant-design-vue
@primary-color: @mainColor;
以下代码中 关键代码是 在 .dark
类名下 @import
专属于 dark 的 color 以及定义专属于 dark 的 css 变量。注意 css 变量名保持 与 .day
统一。
重写第三方库
如果项目中恰好使用了第三方库可以参考第三方库的 less / scss 变量,以及 css 类名重写皮肤。
theme/dark/index.less
less
.dark {
@import "./color.less";
--main-color: @mainColor;
--main-text-color: @mainTextColor;
--main-bg-color: @mainBgColor;
// 重写第三方库className
.ant-radio-button-wrapper {
color: @mainTextColor;
background-color: @mainBgColor;
}
}
2、定义 day 主题 theme/day/color.less
less
@mainColor: #ffffff;
@mainTextColor: black;
@mainBgColor: #f0f2f5;
//覆盖 第三方库主题色 例如 ant-design-vue
@primary-color: @mainColor;
theme/day/index.less
less
.day {
@import "./color.less";
--main-color: @mainColor;
--main-text-color: @mainTextColor;
--main-bg-color: @mainBgColor;
// 重写第三方库className
.ant-radio-button-wrapper {
color: @mainTextColor;
background-color: @mainBgColor;
}
}
内部库
上面的代码使用了 less
如果使用 css
可以参考以下方式
如果内部有多个项目需要换肤 或者多个组件库需要替换变量, 建议将 css 变量和皮肤打包成 npm 包
,各个项目和组件库引用同一个
css npm 包
即可。
css
:root{
--day--main-color: #ffffff;
--day--main-text-color: black;
--day--main-bg-color: #f0f2f5;
--dark--main-color: #01305f;
--dark--main-text-color: #ffffff;
--dark--main-bg-color: #012447;
}
.dark {
--main-color: var(-dark--main-color);
--main-text-color: var(--dark--main-text-color);
--main-bg-color: var(--dark--main-bg-color);
}
.day {
--main-color: var(-day--main-color);
--main-text-color: var(--day--main-text-color);
--main-bg-color: var(--day--main-bg-color);
}
以上只给出了皮肤样式,字体样式结构原理是一样的就不赘述了。
使用
以 Vue
举例:
项目内所有的皮肤颜色和字体大小均使用 css 变量后 我们只需更换 最大容器元素的 皮肤类名 即可做到换肤。
vue
<template>
<div id="app" :class="[theme, fontSize]">
<img src="./assets/logo.png" />
<br />
<a-radio-group :value="fontSize" @change="handleSizeChange">
<a-radio-button value="large"> Large </a-radio-button>
<a-radio-button value="middle"> Default </a-radio-button>
<a-radio-button value="small"> Small </a-radio-button>
</a-radio-group>
<a-radio-group :value="theme" @change="handleThemeChange">
<a-radio-button value="day"> Day </a-radio-button>
<a-radio-button value="dark"> Dark </a-radio-button>
</a-radio-group>
</div>
</template>
<script>
export default {
name: "App",
components: {
HelloWorld,
},
data() {
return {
theme: "day",
fontSize: "middle",
};
},
methods: {
handleSizeChange(e) {
this.fontSize = e.target.value;
},
handleThemeChange(e) {
this.theme = e.target.value;
},
},
};
</script>
<style lang="less">
#app {
height: 100%;
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: var(--main-text-color);
background-color: var(--main-bg-color);
font-size: var(--main-font-size);
}
</style>
其中
css
#app{
color: var(--main-text-color);
background-color: var(--main-bg-color);
font-size: var(--main-font-size);
}
为关键代码
后续所有样式代码用 css 变量替代即可。
其核心原理是:在不同皮肤类名
下实现了相同名称的 css 变量
,它们各自引用了各自的颜色和像素尺寸实现,当 css类名 改变时,类名内部实现的 css 变量 的值也同时改变了。
(完)