在 SaaS 平台中须要实现千人千面,每个租户须要以后平台尽量跟客户公司其余零碎在格调上保持一致。为了尽量减低老本,采取在线换肤的形式解决,做到同一零碎线上同时反对任意套皮肤 (主题) 和新租户无需新的开发。本文探讨不同形式的换肤实现的区别。
预设多主题
经典计划:网站的所有款式代码提前预设一些色彩,在构建的时候生成多份皮肤款式。而后凋谢给用户无限的抉择这几个皮肤,抉择后,替换或者笼罩原来的款式文件。
该计划要害是如何生成多份皮肤款式文件和如何替换款式文件。生成多份款式文件能够利用 less, scss 等 css 预处理语言中的变量能力。在编译时,调整变量生成多份款式文件。生成的款式文件名中,能够携带皮肤名(个别会形象成具备情感色的名次如落日黄),这样在用户抉择新的“皮肤”时,能够替换或者加载(笼罩)新的款式链接,达到切换皮肤的指标。
该计划的毛病:
- 线上只能反对无限数量的皮肤(取决于预埋数量),不能用户自定义色调;
-
款式文件替换非常复杂
- 如果采纳全副款式文件都放在一个文件中,能够简化很多操作。但会极大的减少首屏老本,并且不合乎以后前端组件化开发把款式文件放在组件内容旁边的形式;
- 如果是扩散的款式文件,在切换时,除了要替换以后曾经加载的款式文件,对于新页面的款式文件,也须要加载指定色调款式文件,须要对 webpack 等打包工具做一些优化调整;
所以该计划比拟适宜组件库(以后风行的组件库的主题定制根本也就提供这个能力),不是很适宜整体网站的换肤计划。
该计划能够参考知乎文章:基于 less、sass 的在 webpack 或 vite 等的动静主题的实现计划。
为了反对用户自定义色彩,能够在后端创立一个动静生成指定色调的全款式文件的 API,如 [email protected] 中的在线主题编辑器。但这须要依赖后端能力,且款式文件为动静之后,缓存会受到极大的影响,进而影响加载性能。
对于间接在浏览器中应用 less 或者 scss 等,这个别用于试验性质,会耗费大量客户端性能,不举荐应用。
css in js
如果你的网站应用 css in js 编写,那么换肤性能将会非常容易实现。只须要将主题色从用户上下文中获取后设置到组件上下文中,其余组件通过获取上下文中主题色的值来设置色彩即可。
该计划的毛病:
- 国内很少有团队应用 css in js 开发,很有可能你以后的我的项目不是采纳 css in js 开发;
- 生态有余,很多组件库不是采纳 css in js,须要额定的非凡解决;
这里提供一个对没有应用 css in js 的组件库的非凡解决计划:将组件库的全量款式文件包裹在一个款式组件中,对其中的主题色全副换成 js 变量。
上述组件革新计划毛病:
- 极大减少了组件库降级老本,每次降级都要从新将组件库全量的款式文件进行 css in js 革新
-
失落组件库款式的按需引入能力。如果对每个组件的款式文件都进行革新,那第一轮革新和后续降级的工作量会翻几倍。
css 变量
css 很早以前曾经反对了 css 变量。在应用色调的中央,替换为应用 css 变量,而后管制 css 变量即可换肤。具体计划能够参照知乎文章:基于 Css Variable 的主题切换完满解决方案。
该计划可能存在以下问题:
- 技术还是比拟新,可能以后的我的项目并不是应用 css 变量,革新起来老本太高;
- 不兼容 ie,尽管有垫片,但谁晓得有多少坑在后面等着你;
如果是一个新我的项目,且不须要过多的思考兼容 ie, 强烈建议应用 css 变量进行开发,跟 less,scss 等预处理工具一起应用也没有抵触。
色彩内容替换
假如咱们可能承受,换肤就是把所有 (或者绝大多数) 的色彩 A 的中央都换成色彩 B 的话(除色彩外,其余限定的一些款式值也能够),那么换肤只须要有一种形式找到指标款式值,把它替换成另一个值即可。
浏览器的的 document.styleSheets,能够查问到以后网站上所有的款式内容并且能够批改。如:
// document.styleSheets.item(*).cssRules[*].style[{styleName}] = {updateValue}
document.styleSheets.item(0).cssRules[0].style['color'] = 'red';
该形式在运行时动静设置,不须要调整任何服务器上的源码,计算逻辑都在客户端,且实现原理非常简单。但存下以下致命缺点:
- 每一次的调整只针对于网站曾经加载后的款式,对于后续加载的新款式,还须要额定的逻辑去解决。比方能够每个页面加载实现后的钩子函数中,或者调整构建逻辑 (定制 style-loader) 在款式资源文件加载胜利后批改款式内容;
- 额定耗费客户端计算资源,可能会有一段响应工夫,造成了换肤客户在拜访页面已开始显示默认色调,短暂工夫后,应用指标色调,可能会呈现闪屏景象;
- 因为采取款式比对形式去批改主题色,会造成一个问题:当第一次批改主题色为一个页面已有的其余色彩 (假如为色彩 A) 后,下一次批改主题色时因为此时曾经将色彩 A 也当作时主题色,会把不是主题色含意的色调也调整;
- 如果万一呈现某一个跟主题色一样的值的固定色彩值,须要非凡解决;
尽管该计划存在重大的缺点,但它也有极大的劣势:
- 对老我的项目极度敌对,简直无革新老本;简直兼容老我的项目的任何款式开发方式,也简直兼容任何第三方组件库。
- 对业务开发者十分敌对,简直做到了透明化,除间接写在元素 style 的形式外,不须要减少额定的款式开发标准。
构建时替换成 css 变量
尽管“色彩内容替换”计划有重大缺点,但能够依照其思路进行另一种实现:在构建时就将色彩款式内容替换对应的 css 变量,而后利用 css 变量的能力,反对整个我的项目换肤。
利用 postcss 的技术,能够对我的项目产生的 css 代码进行值的替换。只须要开发 postcss 插件,对 css 内容进行匹配转换。如对应用了主题色色彩的款式,替换成对应的 css 变量。
该计划连续上文中“色彩内容替换”中的长处:兼容老我的项目和第三方组件库。对于其毛病,1- 3 曾经不存在,第四点能够反对特定的源码正文语法(相似 eslint-disable-xxx 形式),疏忽一些状况下的替换,用来适配解决极其状况。
除色彩的替换外,也可用于对于一些其余款式的调整为变量,如字体大小,字体等。让换肤的内容更加丰盛。
存在毛病:
-
不兼容 ie,尽管有垫片,但还是倡议无限成果兼容。
总结
如果不须要兼容 ie 浏览器(或者 ie 浏览器受限拜访),并承受换肤是全局同样色彩值都替换的话,倡议应用“构建时替换成 css 变量”换肤计划。
“构建时替换成 css 变量”能够兼容已有我的项目代码和第三方组件库,简直无任何革新老本。并且也不会新增额定的开发标准,能够间接复制应用 ued 切图进去的款式,进步开发效率。而应用 css 变量等计划,如同国际化,须要整个团队在继续迭代时刻遵循应用变量的标准,一旦治理不到位,容易失控和造成历史债。