当前位置: 首页 > 科技观察

中后端CSSModules的优秀实践

时间:2023-03-12 11:01:34 科技观察

在工作中发现前端CSS的使用是多种多样的,比如Sass、Less等预处理语言,还有CSS在中的精彩玩法JS,以及原子CSS解决方案,例如TailWindCSS。有CSSModules,一种专注于解决局部作用域和模块依赖性的纯技术。种类那么多,我们应该怎么选择呢?下面,我将介绍一种在当前微前端趋势下最适合中后端项目使用的方法,以及开发经验的最佳结合。为什么选择CSSModules我们的最佳实践是基于CSSModules,为什么选择他?在实际工作中,我们遇到的最痛苦的问题就是样式的隔离,尤其是在微前端框架中,子应用之间,子应用与主应用之间,甚至同一个项目的不同页面之间。存在样式覆盖,即使各种微前端框架试图解决样式隔离问题,无论是通过工程加命名空间,还是通过shadowDOM,都无法一劳永逸,有其弊端。与Less相比,Sass是一种在每个页面或组件上人为地想一个命名空间的技术。这个过程没有技术限制。仅仅依靠人与人之间的口头规范是没有用的,但CSSModules无疑是一个完整的解决方案。解决风格冲突问题的方法。CSSModules的文档很简单,10分钟就能学会,基本的主流工程工具和脚手架都支持,比如vite默认支持,CRA也自然支持,不需要额外配置。CSSModules开发体验极佳,写CSS从未如此顺畅,后面会详细介绍。CSSModules+LessCSSModules因为很简单,module.css文件还是遵循CSS文件的规范,所以不能嵌套。为了解决这个问题,我们引入了Less,即使用module.less文件格式,这样我们就可以利用Less编写嵌套代码的能力。为什么不是萨斯?其实Sass和Less在本质上并没有太大的区别,也没有好坏之分。之所以选择Less是因为我的项目使用了很多antd的组件库,而antd使用的是Less方案,如果要自定义antd的主题就必须使用Less。有了Less,可以有效弥补CSSModules的很多不足,尤其是嵌套,比如下面的代码。.container{.header{颜色:红色;}}变量的定义和使用Less和CSSModule都支持变量的定义和使用,下面一一看看如何使用://definecommon.less@width:10px;@height:@width+10px;//使用@import'./common.less';.header{width:@width;height:@height;}//定义colors.css@valueblue:#0c77f8;@valuered:#ff0000;@valuegreen:#aaf200;//使用@valuecolors:"./colors.css";@value蓝色、红色、绿色来自颜色;.title{颜色:红色;background-color:blue;}这两个方法定义和使用都很麻烦,尤其是在使用的时候需要显式导入,我推荐另外一种方法:CSS原生支持的方法。使用文档查看:MDNCSSVariables基本用法如下://定义全局变量:root{--main-color:#fff;}//定义局部变量。container{--main-color:#000;}//使用变量.component{color:var(--main-color);},我们可以看到变量有一个明确的--前缀,这样更容易区分,无需导入,使用方便,覆盖方便。如果我们看antd-mobile最新版本的组件库,这个native方法被广泛用于主题定制和样式覆盖。至于兼容性,在中后台场景,Chrome的支持很好,基本不用考虑。Less中的类复用有基于extend和Mixins的继承方式,但我觉得并不比CSSModules的继承方式方便,尤其是Mixins的反常识用法。而且不容易维护,新手也很难理解。CSSModules的composes使用方法如下://define.container{color:#fff;}//在同一个文件中调用.component{composes:container;}//在不同的文件中调用.component{composes:来自'./index.module.less';color:#000;}如上代码,会被编译成,最终生效的颜色为#000。如何覆盖第三方组件样式?我们在平时的编码中经常会重写第三方组件的样式。比如我们在antd中使用Button样式。在module.less中,我们可以使用:global关键字。只要用到,就不会被编译。使用这个方法的时候会自动加上hash,这样你也可以给他设置唯一父元素的class,这样你改的第三方组件的样式就不会影响其他地方的样式了参考组件。.container{:global(.ant-button){颜色:var(--main-color);}}计算样式类名如果一个组件的类可能需要多个,或者可能需要进行一定的计算,传统的CSSModules的使用方式是比较丑陋的,所以我们使用更优雅的方式来解决,就是使用第三种——派对NPM包,类名的能力。如下://当className需要多个class时,我们直接使用classnames传递多个参数//最终会编译成//如果某个类需要进行某种逻辑判断,可以传入一个对象,使用值的false或true//来控制该类是否存在//这个方法是上面两个方法的结合,classnames可以接收多个参数,对象,甚至数组令人上瘾的开发体验传统写css很难。在JSX的divclassName上,按住cmd+单击可以快速显示或导航到样式代码,但是如果我们使用CSSModules,并且安装了VSCodeCSSModules扩展之后。如下图所示:我们甚至不用切换到Less文件就可以轻松实现定位和展示。当我实际使用它时,我知道它有多酷。当然,使用CSSModules的另一个巨大而明显的好处是我们不需要担心类命名,我们甚至可以在不同的组件中定义相同的名称,例如:importstylefrom'./index.module.less';constLogin=()=>(登录

);constRegister=()=>(注册
);我们看到对于Login和Register组件,我们都使用了两个类container和header,而不需要Prefix组件。这样更有利于代码复用,能够很好的表达页面的结构。编写NPM组件怎么样?在项目的业务代码中使用CSSModules是没有问题的,但是如果我们想把一些组件做成npm包给别人使用,如果使用CSSModules,编译好的npm包也会添加classHash是动态变化的.所以当别人想要覆盖你的样式时,是非常困难的。如何解决这个问题呢?确实,社区已经给出了一些答案,你可以看看下面的文档:customizing-components有两种观点,一种是试图覆盖别人组件的样式,这本身就是一种Hack行为,我们应该使用更优雅的方式来实现,NPM组件应该提供相应的API供外部调用修改。二是社区提供了一个工具包react-css-themr。每个NPM组件都接受外部主题参数(css模块对象),用于定义所有样式。这是一个示例:从'react'导入React;从'react-toolbox/lib/app_bar'导入{AppBar};从'./PurpleAppBar.css'导入主题;constPurpleAppBar=(props)=>();导出默认的PurpleAppBar;以上最佳实践经过本人多年验证,真实有效,绝非自欺欺人。喜欢不喜欢,可以早点尝试享受,晚点用,晚点开心。