你有没有在一个逐渐膨胀的项目中对CSS感到混乱?
样式层层覆盖,大量复制粘贴,命名混乱,修改时出现诸多诡异问题,CSS逐渐走向失控模式。
所以一个好的CSS架构是十分重要的,至少能够满足以下要求:
- 更少的代码和样式冲突
- 便于维护和扩展
- 有较高的复用性
- 便于多人协作和项目交接
- 提升代码书写的幸福感
早在几年前便有人提出了CSS模块化的几种思想,比如OOCSS,SMACSS,Atomic CSS,MCSS,AMCSS,BEM等,每种方案都有利弊,我们各取所长,总结出CSS架构的基本思路就是:
抽象出可高度复用的样式和组件,以语义化为中心,规范全局类名系统
一. 组织结构
规范的css代码文件应具有结构清晰和模块分明的特点,可分为几大类:
1.基本样式 base.css
包括重置元素的默认样式和全局定义的基础样式。
重置的默认样式不是简单粗暴的全部清零,比如*{ margin:0; padding:0;},过度重置往往画蛇添足,可能带来性能问题。可参考Normalize.css,或者总结出一套适合自己的reset.css。
全局定义的基础样式是指单一规则的原子类样式,比如字体,颜色,背景等,来实现重用性。
Atomic CSS就是对重用性最极致的表现,将css拆分到最小的单位,每个类只存一条属性,只需在class中加入对应的类,组合出所需样式,比如:
<a class="f6 link dim br1 ba bw2 ph3 pv2 mb2 dib purple" href="#">Button Text</a>
原子化css虽然简化了样式,但造成html的臃肿,过度抽象带来维护上的巨大成本。最好的css应该是与html无关,而原子类在修改css时增加了很多html的操作。
原子类的最大用处是借鉴它的思想,适当用少量原子类而不是以此为基础来构建页面。
我们可以将通用的属性提取为基础样式,比如:
布局排版 :.fl , .fr , .boxcenter等
全局文字 : 字体,字号,颜色
黑白灰配色 : 这三种颜色几乎是通用的
状态类 : is-active,这类类名用作统一标识,不设默认样式
工具类 :.clearfix , .none , .ellipsis等,用来设置特殊样式规则
至于带数值的,各种颜色的类,没必要大量设置,比如f12,m20,pt30,red-light
2. 布局 layout.css
页面的基本框架,如 .header , .footer , .main , .sidebar, .menu , .nav等
3. 模块 module.css
可复用的组件,比如搜索框,分页,列表,表单,基础按钮样式,select组件等。
4. 响应式 mobile.css
包含媒体查询等移动端样式
5. 其他页面样式文件
二. 命名规范
目前css命名混乱的几种现象为:
- 使用驼峰命名表现元素的从属关系
- 用工程师的名字作为前缀来区分是谁写的
- 以上两者结合产生了较长的class名
- 懒得起名字,定义若干通用原子类(mt20,pb15等),在html中进行堆叠
命名是提高代码可读性的重要步骤,一个规范的类名系统可以解决复用性,兼容性,样式冲突等问题。
对于常见模块可使用一些约定俗成的类名,比如:
头:header,尾:footer,导航:nav,子导航:subnav,主体:main,内容:container/content,侧栏:sidebar,菜单:menu,子菜单:submenu,搜索:search,登录:login,注册:regsiter,热点:hot,标签:tags/tips,信息:msg,栏目:column,状态:status,下载:download,版权:copyright,服务:service,摘要:summary,友情链接:friendlink,广告:banner
对于公共模块可以参考BEM规范,命名模式为B_E_M(BEM规范为B_E--M,我个人不喜欢--,所以简化为B_E_M)。
- B:block 块,代表最高级别的抽象组件
- E:element 元素,代表block的后代
- M:modifier 修饰符,代表block的不同版本或状态
比如:.user , .user_list , .user_list_frist
尽量使用表明模块业务的语义化,甚至可以以整个页面为最大模块单元,采用login_xx,search_xx等命名空间。
由于模块元素都具有同一个类名前缀,因此理论上每个BEM都能抽象为组件。
不需要每个地方都使用BEM命名,取决于它样式的作用域是从哪儿开始和到哪儿结束,灵活使用。
组件设计时尽量遵循单一职责原则,相互独立,可以采取嵌套方式,比如一个头部header里可能包含一个logo,一个搜索search,一个登录login。
通用性的设计是在一定程度上放弃对DOM的掌控,而将DOM结构的控制权转移给开发者,组件只负责行为和最基本的DOM结构,关键在于是否能够把握住页面结构和组件设计的抽象层级。
对于业务功能的class可以使用命名空间前缀来分类,比如:
- 对象类:.o_xx
- 主题类:.t_xx
- 状态类:.is_xx , .has_xx
- 工具类 : .u_xx
- 用于javascript勾子:.js_xx
三. 代码组织
- 尽量避免使用id选择器
- 减少子选择器的层级,大概一到两级
- 使用原子类class时最好不超过3个
- 推荐css书写顺序 : 按类型分组排序 ( 显示,浮动,定位,尺寸,边距边框,字体,背景,其他样式 )
影响页面布局的排到前面:float,margin,padding,height,width等
不影响布局的放到后面:background,color,font等
- 统一良好的编码风格,比如空格,缩进,注释等
四. 基于框架的css组件化
以上为基础的css架构,大型项目还可以搭配 LESS/SASS等预处理器来动态设置样式。
对于现代的web开发出现了许多前端框架,如Vue、React等,相应产生了更加模块化的css处理方式,比如 :Scoped(Vue内置), CSS Modules, Styled Components(React)。
基本思想为CSS IN JS,通过js来管理样式和元素之间的关联,将css的类名成为局部变量,针对框架使用的组合可以扩展为:
- Vue: 基础css架构 + LESS/SASS + Scoped
- React : 基础css架构 + LESS/SASS + CSS Modules/Styled Components