|
前言在项目开发过程中,前端开发人员经常会遇到切换不同主题风格的需求,接下来我们一起来讨论什么是换肤,以及常用的几种换肤方案。一.什么是前端换肤前端换肤最直观的就是颜色的切换,不同主题下,页面的主色调进行改变。常见换肤需求分为两种:静态换肤:提供可选择的主题样式或者颜色进行切换,主题选项比较固定;动态换肤:可以支持自定义色值,比如通过取色板颜色或者后端接口返回,选择范围不固定,比较广泛;动态换肤缓存用户选择的主题,可以考虑以下几种方式:利用路由进行标记;利用缓存:cookie标记、localstorage、native缓存的方法等;保存到后端服务器,接口获取;二.换肤方案介绍1.利用class设置不同的命名空间这种方法比较好理解,原理比较简单,但是维护不同的class代码容易混乱。手动设置不同的class类名就不再详细说,介绍一个工具glup-css-wrap,可以为我们主题的外层包一个class来做命名空间,使用如下://得到以.springtime-theme为命名空间的主题varpath=require('path')vargulp=require('gulp')varcleanCSS=require('gulp-clean-css');varcssWrap=require('gulp-css-wrap');varspringtimeThemeName='.springtime-theme'gulp.task('css-wrap',function(){returngulp.src(path.resolve('./theme/index.css')).pipe(cssWrap({selector:springtimeThemeName})).pipe(cleanCSS()).pipe(gulp.dest('dist'));});gulp.task('default',['css-wrap','move-font']);2.加载不同的css文件进行换肤定义不同的css文件,根据不同主题引入不同的css文件。优点:比较好理解,一个css文件就是一个主题,实现比较简单;缺点:需要手动重写样式表,扩展性不高,不利于支持用户自定义,切换样式需要加载css文件,有一定的加载时间成本;//theme-epipelagic.css//theme-springtime.css//theme-default.css//js动态处理加载不同的css文件functionchangeTheme(themeClass){varlink=document.createElement('link');link.type='text/css';link.rel='stylesheet';link.href='/css/theme-'+themeClass+'.css';document.getElementsByTagName("head")[0].appendChild(link);}consttheme=window.localStorage.getItem(theme);theme=theme?theme[1]:"default";changeTheme(theme);3.利用css预处理器生成多套换肤方案利用Less,stylus或sass的变量代替颜色值,配置多个主题颜色配置,使用webpack打包多个主题样式文件,根据主题,动态下载引入不同css文件进行换肤。优点:扩展性强,不用在手写多套样式;缺点:难理解,配置繁琐,生成冗余代码,切换样式需要时间重新加载css文件,切换不及时,编译速度依赖客户端性能;//scss文件theme.scss$color-springtime:{primary-color:#b7f3ff;}$color-epipelagic:{primary-color:#7bcfff;}@mixinback-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%;@includetext-color(primary-color)}参考文档:https://juejin.cn/post/68449035969921351824.css自定义变量「推荐」使用CSS3内置variable,设置颜色,简单便捷,支持JS修改动态修改变量,使系统颜色变化。优点:代码简单易懂,只需要一套CSS就可自动适配多种主题色,而且页面不会刷新,可自动配置所有的颜色,换肤不需要延时等待;缺点:兼容性不好(IE完全不兼容),无法支持复杂表达式;可以通过安装css-vars-ponyfill解决兼容性问题,css-vars-ponyfill的概念解释(自行翻译):Aponyfillthatprovidesclient-sidesupportforCSScustomproperties(aka"CSSvariables")inlegacyandmodernbrowsers代码示例:css变量生成不同的css文件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:importcssVarsfrom'css-vars-ponyfill';letcurrentTheme='';constonThemeChange=(themeClass)=>{constrootElement=document.documentElement;constcurrenntThemeClass=themeClass||currentTheme;rootElement.setAttribute('data-theme',currenntThemeClass);};constapplyTheme=async(tempThemeName:string)=>{lettheme=tempThemeName;//通过url的参数获取当前theme,也可以通过缓存、请求等方式theme=GetQueryString('theme');if(currentTheme!==theme){currentTheme=theme;onThemeChange();}};//引入css-vars-ponyfill插件做兼容性问题处理cssVars({rootElement:document,shadowDOM:false,onlyLegacy:true,//itwillusemutationobservertowatchchanges,becauseitsupportssafari(6-latest)andchrome(27-latest)//soweneedn'timportthepolyfillformutationobservercurrentlywatch:true,//onBeforeSend(xhr,elm,url){//},//onWarning(message){//},//onError(message,elm,xhr,url){//},//onSuccess(cssText,elm,url){//},//onComplete(cssText,styleElms,cssVariables,benchmark){//}});页面初始化的时候引入css文件,并且调用初始化主题方法import'@/assets/styles/theme/epipelagic.css';import'@/assets/styles/theme/springtime.css';importthemeManagerfrom'@/service/theme-manager';themeManager.applyTheme();//页面样式中用css变量标记样式.order-detail-bg{background-color:var(--primary-color);background-size:100%100%;}.busiunessInfo-contentp {color:var(--second-color);}页面效果:效果1效果25.element-ui中的动态换肤方案ElementUI方案,开启暴力模式,生成一套主题,将主题配色配置写在js中,脚本替换颜色变量,需要使用主色,计算辅色,浏览器中用js动态修改style标签覆盖原有的css,暴力修改应用。实现的大致思路(来自ElementUI官网:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue):优点:通过定义函数的形式自动替换,操作性比较强;缺点:灵活性不够,粗暴简单,实现难度比较高,需要有统一打包出来的index.css;先把默认主题文件中涉及到颜色的CSS值替换成关键词:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L250-L274;根据用户选择的主题色生成一系列对应的颜色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/formula.json;把关键词再换回刚刚生成的相应的颜色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/color.js;直接在页面上加style标签,把生成的样式填进去:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L198-L211;ElementUI官网上也为我们提供了自定义的主题方案:https://element.eleme.io/#/zh-CN/component/custom-theme具体的实现:安装主题生成工具npmielement-theme-g安装element-UI的白垩主题/*从npm*/npmielement-theme-chalk-D/*从GitHub*/npmihttps://github.com/ElementUI/theme-chalk-D初始化变量文件,主题生成工具安装成功后,可以全局安装的可以在命令行中通过et调用工具,如果是当前目录安装可以通过node_modules/.bin/et访问到命令。初始化变量文件,默认会输出element-variables.scss,也可以指定参数,指定文件输出的目录://或者node_modules/.bin/et-i//如果这一步遇到报错ReferenceError:primordialsisnotdefined,解决办法:npmielement-themex-get-i[可以自定义变量文件]✔Generatorvariablesfileelement-variables.scss文件内容:/*ElementChalkVariables*///Specialcommentforthemeconfigurator//type|skipAutoTranslation|Category|Order//skipAutoTranslation1/*Transition--------------------------*/$--all-transition:all.3scubic-bezier(.645,.045,.355,1)!default;$--fade-transitionpacity300mscubic-bezier(0.23,1,0.32,1)!default;$--fade-linear-transitionpacity200mslinear!default;$--md-fade-transition:transform300mscubic-bezier(0.23,1,0.32,1),opacity300mscubic-bezier(0.23,1,0.32,1)!default;$--border-transition-base:border-color.2scubic-bezier(.645,.045,.355,1)!default;$--color-transition-base:color.2scubic-bezier(.645,.045,.355,1)!default;/*Color--------------------------*////color|1|BrandColor|0$--color-primary:#409eff!default;///color|1|BackgroundColor|4$--color-white:#FFFFFF!default;///color|1|BackgroundColor|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*/...//太多就不放在这里展示了直接编辑element-variables.scss文件,比如修改$--color-primary主题颜色编译主题,命令行里执行et编译主题/*-w开启watch模式-c指定自定义变量参数-o指定打包目录*/et✔buildthemefont✔buildelementtheme6.ant-design中换肤方案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.jsmodule.exports={rules:[{test:/\.less$/,use:[{loader:'style-loader',},{loader:'css-loader',//translatesCSSintoCommonJS},{loader:'less-loader',//compilesLesstoCSS+options:{+lessOptions:{//如果使用less-loader@5,请移除lessOptions这一级直接配置选项。+modifyVars:{+'primary-color':'#1DA57A',+'link-color':'#1DA57A',+'border-radius-base':'2px',+},+javascriptEnabled:true,+},+},}],//...otherrules}],//...otherconfig}//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',},});三.附加:其他换肤方案我们在app中会看到页面整体会变为灰色的情况,可以通过这个属性可以实现:html{filter:grayscale(1)}css效果filter的其他特性和对应效果小程序如何进行换肤因为小程序技术的特殊性,所以传统的前端换肤方案没法在小程序中使用,这里提供几种小程序的换肤方案供参考:如果没有线上存在多套皮肤的需求,可以抽取颜色变量通过线下编译修改主题色;如果有线上多套皮肤的需求,则采用传统前端的多套CSS皮肤方案加更改类名的方式;针对动态换肤,后端接口返回色值字段,前端通过内联方式对页面元素进行色值设置;参考文档:https://zhuanlan.zhihu.com/p/407434343?utm_source=wechat_session&utm_medium=social&utm_oi=1350733647192981504作者简介❝屈会敏:出发永远是最有意义的事情,去做就对了❞
|
|