在项目开发过程中,前端开发人员经常会遇到切换不同主题风格的需求,接下来我们一起来讨论什么是换肤,以及常用的几种换肤方案。
前端换肤最直观的就是颜色的切换,不同主题下,页面的主色调进行改变。
常见换肤需求分为两种:
动态换肤缓存用户选择的主题,可以考虑以下几种方式:
这种方法比较好理解,原理比较简单,但是维护不同的 class 代码容易混乱。手动设置不同的 class 类名就不再详细说,介绍一个工具glup-css-wrap
,可以为我们主题的外层包一个 class 来做命名空间,使用如下:
// 得到以.springtime-theme为命名空间的主题
var path = require('path')
var gulp = require('gulp')
var cleanCSS = require('gulp-clean-css');
var cssWrap = require('gulp-css-wrap');
var springtimeThemeName='.springtime-theme'
gulp.task('css-wrap', function() {
return gulp.src( path.resolve('./theme/index.css'))
.pipe(cssWrap({selector:springtimeThemeName}))
.pipe(cleanCSS())
.pipe(gulp.dest('dist'));
});
gulp.task('default',['css-wrap','move-font']);
定义不同的 css 文件,根据不同主题引入不同的 css 文件。
// theme-epipelagic.css
// theme-springtime.css
// theme-default.css
// js动态处理加载不同的css文件
function changeTheme(themeClass) {
var link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = '/css/theme-'+ themeClass +'.css';
document.getElementsByTagName("head")[0].appendChild(link);
}
const theme = window.localStorage.getItem(theme);
theme = theme ? theme[1] : "default";
changeTheme(theme);
利用 Less,stylus 或 sass 的变量代替颜色值,配置多个主题颜色配置, 使用 webpack 打包多个主题样式文件,根据主题,动态下载引入不同 css 文件进行换肤。
// scss文件 theme.scss
$color-springtime: {
primary-color: #b7f3ff;
}
$color-epipelagic: {
primary-color: #7bcfff;
}
@mixin back-color($key) {
background-color: map-get($color-springtime, $key);
[data-theme='epipelagic'] & {
background-color: map-get($color-epipelagic, $key);
}
}
// 页面中进行使用
@import 'theme.scss';
.page-loading {
background-size: 100% 100%;
@include text-color(primary-color)
}
参考文档:https://juejin.cn/post/6844903596992135182
使用 CSS3 内置 variable,设置颜色,简单便捷,支持 JS 修改动态修改变量,使系统颜色变化。
可以通过安装
css-vars-ponyfill
解决兼容性问题,css-vars-ponyfill
的概念解释(自行翻译):A ponyfill that provides client-side support for CSS custom properties (aka "CSS variables") in legacy and modern browsers
代码示例:
html[data-theme='epipelagic']:root {
--primary-color: #7bcfff;
--second-color: #00a2ff;
}
html[data-theme='springtime']:root {
--primary-color: #35BB9A;
--second-color: #096951;
}
theme-manage.js
:
import cssVars from 'css-vars-ponyfill';
let currentTheme = '';
const onThemeChange = (themeClass) => {
const rootElement = document.documentElement;
const currenntThemeClass = themeClass || currentTheme;
rootElement.setAttribute('data-theme', currenntThemeClass);
};
const applyTheme = async (tempThemeName: string) => {
let theme = tempThemeName;
// 通过url的参数获取当前theme,也可以通过缓存、请求等方式
theme = GetQueryString('theme');
if (currentTheme !== theme) {
currentTheme = theme;
onThemeChange();
}
};
// 引入css-vars-ponyfill插件做兼容性问题处理
cssVars({
rootElement: document,
shadowDOM: false,
onlyLegacy: true,
// it will use mutation observer to watch changes, because it supports safari(6-latest) and chrome(27-latest)
// so we needn't import the polyfill for mutation observer currently
watch: true,
// onBeforeSend(xhr, elm, url) {
// },
// onWarning(message) {
// },
// onError(message, elm, xhr, url) {
// },
// onSuccess(cssText, elm, url) {
// },
// onComplete(cssText, styleElms, cssVariables, benchmark) {
// }
});
import '@/assets/styles/theme/epipelagic.css';
import '@/assets/styles/theme/springtime.css';
import themeManager from '@/service/theme-manager';
themeManager.applyTheme();
// 页面样式中用css变量标记样式
.order-detail-bg {
background-color: var(--primary-color);
background-size: 100% 100%;
}
.busiunessInfo-content p {
color: var(--second-color);
}
页面效果:
ElementUI 方案, 开启暴力模式,生成一套主题,将主题配色配置写在 js 中,脚本替换颜色变量,需要使用主色,计算辅色,浏览器中用 js 动态修改 style 标签覆盖原有的 css,暴力修改应用。
实现的大致思路(来自 ElementUI 官网:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue):
npm i element-theme -g
/* 从 npm */
npm i element-theme-chalk -D
/* 从 GitHub */
npm i https://github.com/ElementUI/theme-chalk -D
// 或者node_modules/.bin/et -i
// 如果这一步遇到报错ReferenceError: primordials is not defined,解决办法:npm i element-themex -g
et -i [可以自定义变量文件]
✔ Generator variables file
/* Element Chalk Variables */
// Special comment for theme configurator
// type|skipAutoTranslation|Category|Order
// skipAutoTranslation 1
/* Transition
-------------------------- */
$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default;
$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
$--fade-linear-transition: opacity 200ms linear !default;
$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default;
$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default;
/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: #409eff !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--color-black: #000000 !default;
$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */
$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */
$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */
$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */
$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */
$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */
$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */
$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */
$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */
...
// 太多就不放在这里展示了
/*
-w 开启watch模式
-c 指定自定义变量参数
-o 指定打包目录
*/
et
✔ build theme font
✔ build element theme
ant.design 官网中切换主题,是在 html 标签加里 color-scheme 和在 body 里添加自定义标签 data-theme="dark",和:root 配合改变。
CSS 属性允许元素指示它可以轻松呈现的配色方案,操作系统配色方案的常见选择是“亮”和“暗”,或者是“白天模式”和“夜间模式”,antd 的样式使用了 Less 作为开发语言,并定义了一系列全局/组件的样式变量,我么根据需求动态修改 css 变量实现换肤。
所有的 antdesign 的样式变量:
https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
// 1. 在webpack中定制主题
// webpack.config.js
module.exports = {
rules: [{
test: /\.less$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader', // translates CSS into CommonJS
}, {
loader: 'less-loader', // compiles Less to CSS
+ options: {
+ lessOptions: { // 如果使用less-loader@5,请移除 lessOptions 这一级直接配置选项。
+ modifyVars: {
+ 'primary-color': '#1DA57A',
+ 'link-color': '#1DA57A',
+ 'border-radius-base': '2px',
+ },
+ javascriptEnabled: true,
+ },
+ },
}],
// ...other rules
}],
// ...other config
}
// 2. 配置less变量文件进行覆盖
@import '~antd/es/style/themes/default.less';
@import '~antd/dist/antd.less'; // 引入官方提供的 less 样式入口文件
@import 'your-theme-file.less'; // 覆盖上面定义的变量
// 替换引入 antd.variable.min.css
-- import 'antd/dist/antd.min.css';
++ import 'antd/dist/antd.variable.min.css';
// 调用 ConfigProvider 配置方法设置主题色:
import { ConfigProvider } from 'antd';
ConfigProvider.config({
theme: {
primaryColor: '#25b864',
},
});
html { filter:grayscale(1) }
参考文档:https://zhuanlan.zhihu.com/p/407434343?utm_source=wechat_session&utm_medium=social&utm_oi=1350733647192981504
❝屈会敏:出发永远是最有意义的事情,去做就对了
❞
LBG开源项目推广:
还在手写 HTML 和 CSS 吗?
还在写布局吗?
快用 Picasso(毕加索) 吧!
一键生成高可用的前端代码,让你有更多的时间去沉淀和成长
开源项目地址:https://github.com/wuba/Picasso (欢迎Star)
官网地址:https://picassoui.58.com