当前位置: 首页 > Web前端 > vue.js

关于前端主题切换的思考以及现代前端风格落地的解决方法

时间:2023-04-01 00:29:17 vue.js

demo在线体验地址:v-theme-colors源码地址:v-theme-colors(ps大部分功能没有同步发布)1.给网站换肤或者应用一键切换主题(简称:换肤)功能,这个功能对于每个前端开发者来说都是很常见的,通常是一深一浅,或者自由组合衍生出很多主题,或者任意主题.这时候,设计一个工程化的主题切换功能和梳理现代前端风格的解决方案就显得尤为重要。2.皮肤变化的研究很久以前,通常的做法是为每个颜色主题块写一个样式表,切换时相应切换。现代前端主题切换——目前主流的解决方案往往是通过CSS变量(CSS自定义属性)来实现的,将与主题相关的颜色以业务化、语义化的方式命名。接下来我们看看前端圈的知名UI是怎么做的:(1)ElementUI我们可以看element-plus的官网,主题切换主题是和主题相关的变量带有class="dark"的html标签。基于html.dark,更改为:root。当然我们也可以通过源码看到element-plus使用了scss。(2)ant.design我们可以去ant.design的官网看看。主题切换主题是在html标签中添加color-scheme,在body中添加自定义标签data-theme="dark",改成:root。CSS属性允许元素指示它可以轻松呈现的配色方案。操作系统配色方案的常见选择是“亮”和“暗”,或“白天模式”和“夜间模式”。当用户选择其中一种配色方案时,操作系统会调整用户界面。这包括表单控件、滚动条和CSS系统颜色的使用值。通过源码我们也可以看出ant用的比较少。3.Skinning痛点与思考(1)如前所述,ElementUI和ant都使用不同的CSS预处理器(sass和less)来组织代码,在微前端盛行的时代,如何设计一个通用的多团队Skinning是否提供CSS自定义属性和de-css预处理?(2)谁来维护不同的主题色,研发和设计之间如何保持不同主题色值的同步沟通?(3)如何在不做多种主题色的情况下,最大限度地减少前端工程师的开发量?(4)...基于以上考虑,比如我们希望在开发的时候写成:.text{color:var(--c-color)}这样一劳永逸——直接支持两套或多套主题图案。但是业务往往是千变万化的,就像我们公司:(1)换皮的需求就是要有一个颜色(阴影),然后根据深浅,衍生出很多主题色,比如深蓝色,深黄、深红、浅蓝、浅黄、浅红……(2)深浅,有一些基本色。对于组件颜色,通常一套基本颜色就??够了,但业务页面可能会涉及到千变万化的颜色。..4。换肤结构如上图所示,我们可以将换肤升级为平台或中台:(1)对于UED同学,可以自行配置换肤相关的系统颜色和衍生主题颜色。系统颜色系统颜色系统基础色(2)针对每个前端团队,通过主题色、颜色系统基础色,可以任意自定义配置业务所需颜色的变量。使用基于css-vars-ponyfill的换肤方案,至于其优点,正如官方所描述的那样,pnyfill为传统和现代浏览器中的css自定义属性提供了客户端支持。[1]本方案亮点及规则(1)纯JS实现,对外暴露initThemes初始化方法,不依赖CSS预处理器(sass和less),兼容ie9(2)提取dark和dark基础色浅色(统一管理输出),以及主题色和混合色(黑白)可以通过动态接口获取(3)统一规范的业务颜色常量命名,JS定义自定义函数方法1.Mix函数实现了一个媲美sass的混色机制。2、系统与RGB(rgba)十六进制转换函数(4)技术路线不动摇,直接用var()函数即可,后期打包成JS库,可提供皮肤配置平台给各个团队使用(5)关于业务自定义变量,设计了两种治理方案:(1)全局变量,全局单独维护(2)局部业务变量,本地单独维护[2]核心原则(1)当应用端触发换肤操作时,配合JavaScript状态管理,同步主题切换的信号,相应触发initThemes方法//测试新主题letvarList={...colorColor}lettPrimaryList=themePrimaryListinitThemes('',tPrimaryList,varList,'')(2)切换主题颜色甚至业务下变量对应的值,通过css-vars-ponyfill,打自定义常量到t对应的DOM节点(一般在html或body下),从而切换主题hex2rgb}from"./com/util";/***initThemes全局初始化主题*@paramthemetheme[required]*@paramtPrimaryListthemelist[required]array['theme1','theme2']*@paramvalList自定义主题列表{val1:['theme1-color','theme2-color']}....*@paramthemeType主题类型-Darkness....*@paramchangeType区分主题类型和主题颜色[保留字段]....*@returns{boolean}*/exportconstinitThemes=(theme,tPrimaryList,varList,themeType)=>{letvariables=getVariables(theme||"lightBlue",tPrimaryList,varList,themeType);cssVars({watch:true,//ponyfill会自动调用variables:variables,//variables是自定义属性名/值对的集合onlyLegacy:false,//false默认将css变量编译成浏览器可识别的css样式true编译当浏览器不支持css变量时的css变量css用于识别});};themeList.js这里有一些主题和颜色系统(深色和浅色)我们假设我们在应用程序端设置的基本颜色import{light}from'./com/light'import{dark}from'./com/dark'//theme-主题颜色exportconstthemePrimaryList={dark:[{color:'#FFAA0E',name:'darkyellow',theme:'darkYellow'},{color:'#FFAA0E',name:'DarkBlue',theme:'darkBlue'},],light:[{color:'#FFAA0E',name:'DarkYellow',主题:'lightYellow}'},{颜色:'#256DFF',名称:'浅蓝色',主题:'lightBlue'}]}exportconstthemeTypeList={dark:dark,light:light,}【3】色组&色值平台设计对于前端用户,我们只需要关注具体的常量以及如何设置即可持续的比如我们公司根据业务定义了一些常用的语义业务常量,比如//功能颜色"--c-primary":color.C00,//主题颜色"--c-primary-rgb":hex2rgb(color.C00),//主题色RGB"--c-primary-hover":mix(white,color.C00,12),"--c-primary-active":mix(black,color.C00,12),"--c-fill-primary":mix(white,color.C00,88),//主题色文本的背景填充色"--c-border-primary":mix(white,color.C00,80),//主题色文本的边框颜色"--c-primary-mix-1":mix(white,color.C00,10),"--c-primary-mix-2":mix(white,color.C00,20),"--c-primary-mix-3":mix(white,color.C00,30),"--c-primary-mix-4":mix(white,color.C00,40),"--c-primary-mix-5":mix(white,color.C00,50),"--c-primary-mix-6":mix(white,color.C00,60),"--c-primary-mix-7":mix(white,color.C00,70),"--c-primary-mix-8":mix(white,color.C00,80),"--c-primary-mix-9":mix(白色,彩色r.C00,90),"--c-success":color.C01,//成功颜色"--c-warning":color.C01,//警告颜色"--c-error":color.C01,//错误颜色"--c-green":color.C06,//语义绿色"--c-green-rgb":hex2rgb(color.C06),"--c-green-hover":mix(white,color.C06,12),"--c-green-active":mix(black,color.C06,12),"--c-red":color.C08,//语义红色激活"--c-red-rgb":hex2rgb(color.C08),"--c-red-hover":mix(white,color.C08,12),"--c-red-active":mix(black,color.C08,12),"--c-yellow":color.C07,//语义黄色"--c-yellow-rgb":hex2rgb(color.C07),"--c-yellow-hover":mix(white,color.C07,12),"--c-yellow-active":mix(black,color.C07,12),//文本颜色"--c-text":color.C02,//generaltext"--c-text-title":color.C02,//title"--c-text-subtitle":hex2rgb(color.C02,0.65),//副标题"--c-text-info":hex2rgb(color.C02,0.45),//提示"--c-text-placeholder":color.C02,//占位符文本颜色"--c-text-link":color.C01,//链接文本颜色"--c-text-disable":hex2rgb(color.C02,0.3),//禁用或无效//填充颜色"--c-fill":color.C04,//组件默认背景色"--c-fill-body":color.C11,//页面背景"--c-fill-shadow":hex2rgb(color.C11,0.1),//阴影"--c-fill-zebra":color.C05,//斑马色"--c-fill-mask":color.C11,//遮罩背景"--c-fill-disable":hex2rgb(color.C02,0.07),//禁用"--c-fill-scroll":hex2rgb(color.C02,0.5),//滚动条颜色"--c-fill-scroll-hover":mix(white,color.C02,12),"--c-fill-scroll-active":mix(black,color.C02,12),//边框/分隔线颜色"--c-border":color.C01,//基本边框颜色"--c-border-line":hex2rgb(color.C02,0.07),//分割线"--c-border-light":hex2rgb(color.C02,0.12),//浅色边框颜色(小边框)"--c-border-lighter":hex2rgb(color.C02,0.07),//浅色"--c-border-disable":hex2rgb(color.C02,0.04),//禁用边框//图标颜色"--c-icon":hex2rgb(color.C02,0.65),"--c-icon-hover":color.C09,"--c-icon-active":color.C01,"--c-icon-down":color.C10,//Tab颜色//...getTabColor(color),//业务自定义-写在业务端变量中//从主题切换时动态传递在ImportedcustomvariablelistvarList...getBusinessVars(theme,type,varList,tPrimaryList)中,使用时只需要熟悉这些语义常量即可。当然,我们也设计了可视化页面,可以看到自定义变量的全量定义变量和对应的颜色,更方便全局查看。当然,对于上面的混合代码,你可能看起来有点奇怪。这是我们UED同学为了减少颜色(比如浮色,按照8.8是默认颜色和1.2混合成白色计算的一套颜色规范;压色是8.8混合成默认计算的color和1.2变成black),比如mixedMix函数(颜色混合规则符合scss-mix),剩下的就是RGB和十进制颜色转换等函数【4】获取当前主题中的自定义变量color自定义变色:对于业务来说,基础色不一定能满足所有业务的颜色覆盖,或者每个主题下的基础色没有一一对应。这时候自定义可变颜色的功能就变得必不可少了。主要原理是可以根据每个主题(极端情况)填写对应的业务需要的颜色,这里也分为以下两种场景:(1)完全自定义常量多态,即一个主题颜色自定义常量有对应一种颜色例如有四种系统主题[dark1,dark2,light1,light2],某业务背景颜色,我们定义一个常量--color-codercao-fill01即:dark1主题是基本色dark.C01;dark2主题下的颜色是基础色dark.C02;light1主题下的颜色是基础色light.C03;light2主题下的颜色是#fff;此时,这种情况属于极端情况,在每个主题下,我们的自定义常量对应四个主题,四种颜色,颜色是不规则的,可能是基础色,也可能是任意颜色。--color-codercao-fill01:['dark.C01','dark.C02','light.C03','#fff'](2)自定义常量多态性只与深浅相关,只与基础色的深浅相关相关颜色比如有四种系统主题[dark1,dark2,light1,light2],某业务背景色,我们定义一个常量--color-codercao-fill02即:dark1和dark2dark下的颜色主题是A基本色#555;light1和light2的灯光主题下的颜色是基础色#fff;此时,在本例中,我们的自定义常量对应四个主题,只有两种颜色,可能是基础色,也可能是任意颜色。--color-codercao-fill02:['#555','#fff']//主题变量color.vue//(1)完全自定义常量多态,一种主题色对应一种颜色”--color-codercao-test0":mergeColor(["#444","#666"],["#444","#666"],type,theme,tPrimaryList),//(2)只涉及深度常量多态性,颜色只涉及深浅基础色"--color-codercao-test1":mergeColor([dark.C01],[light.C02],type),我们需要根据主题动态变化计算,所以我们有设计一个计算颜色的方法,获取每个主题下的颜色,主题,主题列表,甚至主题类型来计算当前主题下这个变量的颜色使用哪种颜色/***mergeColor得到的当前主题下该变量(自定义)的颜色*@paramdarkList[required]不同主题下自定义常量的深色颜色列表array['theme1','theme2']*@paramlightList[required]中的自定义常量不同的主题l浅色列表数组['theme1','theme2']*@paramtype主题类型dark-light*@paramthemethemecolor-name*@paramtPrimaryListthemelist*@returns{boolean}*/constmergeColor=(darkList,lightList,type,theme,tPrimaryList)=>{让colorList=type=="dark"?暗表:亮表;让color=colorList[0],index=0;//如果类型一个值表示自定义主题常量只与基色(两种)相关if(!theme){color=type=="dark"?暗列表[0]:亮列表[0];}else{//否则将其视为主题和颜色值index=getThemeIndex(theme,tPrimaryList);color=colorList[索引];}返回颜色;};另一种极端情况是可以在对应的DOM中自定义css变量接下来我们就可以愉快的换皮玩啦~6.总结本换皮方案基于css-vars-ponyfill插件,使用纯JS来实现写换皮的核心函数,然后将其转换为更具语义的业务(功能)变量颜色,然后匹配主题以相应地更改特定颜色,并保留自定义变量的功能,使皮肤更改更加有灵魂。当然,如果大家有更好的想法,可以在评论区一起探讨和分享。Demo在线体验地址:v-theme-colors源码地址:v-theme-colors(ps大部分功能暂未同步发布)