浅谈CSS架构

438 阅读5分钟

你有没有在一个逐渐膨胀的项目中对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