手把手从零到一打造在线文档(外传)之 CSS 样式架构方案
前言
一般情况而言,对于样式基本上都是对照设计图 一把梭,高度还原设计图就好了。然后再好一点的就是根据 模块 或者说 组件 对 className 进行一定 语义化 的命名就完事了。至于什么 CSS 架构 大概很多人的第一反应可能是 黑人问号.jpg ,啥玩意?CSS 还有架构??
是的 CSS 也是可以有架构的,同样 CSS 也是有 "设计模式" 的,通过结合 CSS 的设计模式进行 CSS 的架构搭建,能有效的提高 CSS 的 可维护性和复用性以及可读性。至于是否能提升开发效率这件事我个人觉得可能要分情况以及项目类型了,但总归是 有收益 的,而且好的 CSS 架构设计确实能让人少写很多的 CSS 代码。
CSS 设计模式
CSS 的设计模式大致可以分为五种,分别是:OOCSS、BEMCSS、SMACSS、ITCSS、ACSS
。
PS1:这些 CSS 的设计模式并 不是 特指某种处理 CSS 代码的 插件或工具,而是 CSS 的编写 方法和规范,可以说是一种 编程思想。
PS2:这里也只是对这几种 CSS 的设计模式做一些 粗浅的介绍,想要深入的话还需要自行查找相关的资料,同时算是我对 CSS 架构的学习的归纳,所以有部分是自己的理解,如果有理解上的 差异或错误 的地方,欢迎指正和讨论。
OOCSS
OOCSS 其实就是 面向对象 的 CSS,以面向对象的思维来写 CSS,OO
是 Object Oriented
的缩写。
至于什么是 面向对象编程 这里就不做过多的叙述了,简单来讲世间万物都可以归类到某个对象(类)中,比如 动物 这个对象(类),然后通过对其进行衍生就可以有 狗、猫 等等的子对象(类),我们可以把事物抽象出基础的对象(类),然后用基础的对象(类)去衍生其他的子对象(类),来提高代码的 复用性、可维护性 啥啥的。
建议哈,可以专门的去找一找面向对象的文章或视频去深入的了解一下,面向对象还是很重要的知识点,咱这里描述可能不是那么准确。
OOCSS 有两种基本原则:
- 原则一:容器与内容分离;
- 原则二:结构与风格分离;
容器与内容分离
OK,把这些框框按照业务模块或者组件进行划分,基本上就可以算作对应模块的 容器 了(每个人的理解和习惯都不一样,所以对业务进行划分的粒度和方式都不一样,根据个人喜好来哈,这只是我习惯的划分方式)。
来写一个 伪代码 具体看看如何:
// css 代码
.list-item { css code }
.list-item-block { css code }
// html 代码 图 1
<li class="list-item">
<div class="list-item-block">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
//... 根据情况设计使用多个块
</li>
// html 代码 图 2
<li class="list-item">
<div class="list-item-block">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
//... 根据情况设计使用多个块
</li>
那么在容器固定的情况下,内容是不是就可以随意进行定制化的开发了?这就是 容器和内容分离,有没有一种 组件化 开发的即视感,滑稽。
同时 容器与内容分离 有一个简单的准则就是,避免使用 CSS 的子选择器或者说后代选择器,而是使用唯一的类,同样举个栗子:
// 错误示范
.list-item { css code }
.list-item > div { css code }
<li class="list-item">
<div>{ 内容 }</div>
<div>{ 内容 }</div>
</li>
上面的栗子中就通过 后代选择器 对 div 进行了样式设置,那么这种写法就限定了 html 的结构,如果有其他类似的 列表 需要修改结构或有人不小心 变更了 html 的结构,就会导致 css 样式失效,并且需要 重新书写 css 代码,而且作用于 div 上的样式可能在其他地方也有用到,但是由于后代选择器的缘故导致 无法进行复用。
结构与风格分离
一般来说,可以对我们常用的 CSS 进行一个简单的归类,一类是用于 布局 的样式,例如:width、height、padding、margin、position、float
等;一类是用于 装饰 提供不同展示效果的样式,例如:font、color、background、border
等;
那么可以简单的把用于布局的样式归属于 结构类型 中,把用于装饰不影响布局的样式归属 风格类型 中。
图上所示,两个列表项的结构没有变,只是 标题 的文案颜色变了,这个时候我们就可以把 颜色(风格) 独立出来做成一个单独的 className ,对上述 伪代码 进行一下改造来具体看看如何:
// css 代码
.list-item { css code }
.list-item-block { css code }
.font-color-grey { color: grey }
// html 代码 图 1
<li class="list-item">
<div class="list-item-block">{ 内容 }</div>
// 在标题这一栏添加 风格 的 className
<div class="list-item-block font-color-grey">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
</li>
// html 代码 图 2
<li class="list-item">
<div class="list-item-block">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
<div class="list-item-block">{ 内容 }</div>
</li>
OK,这么一看是不是对 结构与风格 有了一个 基本的概念 了?风格也可以理解成 皮肤 的意思。
OOCSS 的优缺点
优点
- 可扩展性,可以通过自由搭配和组合的形式进行扩展而不需要反复对基础对象进行修改;
- 可维护性,对 html 结构进行变动的时候,一定程度上可以无需重新编写 css 代码;
- 减少 CSS 文件大小,OOCSS 能有效的对样式进行复用,可以少写很多的样式代码,从而减少样式文件的体积。
缺点
- 学习成本,使用 OOCSS 拥有一定的学习成本;
- 数量繁多的 className 一定程度上提高了项目样式规范的复杂度;
- 使用成本,规范和设计基础对象以及风格需要一定的人力成本和时间成本,如果是小型项目或临时项目都可以不需要考虑可扩展性、可维护性;
- className 无语义化,OOCSS 并没有对 className 命名的相关规范和约束,所以可能导致很多意义不明的 className 出现。
BEMCSS
BEMCSS 简单来说可以理解成是一种 CSS className
的 命名规范,BEMCSS 是由 Yandex
团队提出的一种 CSS 命名 方法论。
BEMCSS 将命名分为了三层:块(Block)、元素(Elmenet__)、修饰符(Modifier--)
。
同样用之前的 伪代码 来举个栗子:
// css 代码
.article { css code } // 块
.article__element { css code } // 元素
.article__element--grey { color: grey } // 修饰符
// html 代码 图 1
<li class="list-item">
<div class="article__element">{ 内容 }</div>
// 在标题这一栏添加 修饰符 的 className
<div class="article__element article__element--grey">{ 内容 }</div>
<div class="article__element">{ 内容 }</div>
</li>
不知道大家有没有发现,除了命名不一样以外,其他的和 OOCSS 的基本上是一样的,甚至可以说是一毛一样,我个人觉得哈 BEMCSS 可以说是升级版本的 OOCSS,在 OOCSS 的基础上 解决了 className 无语义化的问题,并且进一步的提升了 可读性和可维护性 方面的能力。
通过上述可以知道使用 BEMCSS 需要遵守三个基本原则:
- 使用
__
两个下划线将块名称和元素名称进行分隔; - 使用
--
两个破折号将元素名称和修饰符进行分隔; - 使用 描述性 的类名。
OK,当然部分人可能会觉得使用 __
和 --
进行分隔很奇怪或不符合 个人、团队的喜好,所以可以根据不同的情况来 约定 具体使用什么符号作为分隔符,例如 -
和 _
。
PS:相信使用过开源组件库的兄弟们肯定对 BEMCSS 的规范很眼熟。
SMACSS
SMACSS 是一个转折点,SMACSS 和 BEM 以及 OOCSS 不一样的是,SMACSS 出现了对 CSS 代码组织结构上的分类或者说分层。
以我不成熟的理解来说,SMACSS 就已经算是一种 CSS 架构方案 了,并且 SMACSS 是 Scalable and Modular Architecture for CSS
的缩写,用翻译软件直接翻译过来就是 CSS 的可扩展和模块化架构。
SMACSS 的分类一共有五种类型:
- Base - 基础
- Layout - 布局
- Module - 模块
- State - 状态
- Theme - 主题
SMACSS 最核心的就是提出了 分类 的思想,至于每个类的规则反而不太重要。
PS: 虽然 SMACSS 对每个分类都有自己的一套规则和约定哈,但是我感觉部分规范可能不太适合现在的开发模式了,感兴趣的可以去 SMACSS 的官网查看具体每个分类的规则,我这里就不太过多的介绍每个分类的规则了,就大致说说每个分类的作用和定位。
Base | 基本规则
用过 jQuery
写过静态页面的兄弟应该会对 reset.css
这个不陌生,然后大部分的兄弟应该都不会对 normalize.css
有陌生感。没错这两个 css 文件的内容就可以作为 Base
层,也就是说 Base
层的作用基本上就是让所有 HTML 元素 在不同浏览器上看着都一样。
官方示例如下:
html, body, form { margin: 0; padding: 0; }
input[type=text] { border: 1px solid #999; }
a { color: #039; }
a:hover { color: #03C; }
Layout
这个其实就比较好理解了,字面上的意思,就是用于页面布局的样式,例如 header、sider、footer、content、container、栅格
等等。
Module
SMACSS 中对模块规则的定义是 可以重复使用的模块化部分,例如:标注、侧边栏、产品列表
等。用 SMACSS 的话来说就是 次级组件 可以在布局中 复用和挪动位置 的。
基本上可以理解成被日常开发中的 基础组件 和 业务组件 的概念。
State
状态规则描述的是,我们的 Module
和 Layout
在 特定情况 下的展示形式,例如:显示、隐藏、选中、禁用、激活、错误、正确
等等。
基本上是用于 交互 中的特定样式显示,常用样式有 .is-active .is-open
之类的。
Theme
这个没啥说的了,基本就是为了解决 换肤/主题 功能衍生出来的分类,切换不同风格的样式,大部分情况都是 颜色、边框、字体
等装饰性样式,甚至很多情况下都不需要这一个分类。
ITCSS
ITCSS 同样是一个拥有对 CSS 代码组织结构上进行了分层的架构方案,同时 ITCSS 是能和 CSS 预处理器结合到一起使用的方案。
ITCSS 是 Inverted Triangle Cascading Style Sheets
的缩写,用翻译软件翻译过来就是 倒三角形级联样式表 的意思,所以它的分层展示也是使用了 倒三角模型。
ITCSS 把 CSS 代码组织结构分为了 七层,越是在上方的层次,它的 权重 就会越低,复用性 也就会越高,需要注意的是 ITCSS 的下一层永远可以 继承(复用) 它的上一层样式!
ITCSS 与 SMACSS 的区别主要是 层次分的更细,并且 ITCSS 更契合现代浏览器项目。
ITCSS 在工作流程和工具方面非常 灵活,也没有规定或者说固定的模板之类的,这些都取决于你自己的抉择,同时 ITCSS 没有规定需要所有层都存在,并且可以根据情况 自行增删以及调整层的顺序。
Setting
整个项目样式的一些变量,例如:颜色、字体、边框、阴影
等变量。
Tools
整个项目样式的一些工具库,例如:预处理器中的 mixin
和 function
,具体点就是如清除浮动、文字溢出显示省略号等样式。
Generic
跟 SMACSS 的 Base 层比较相似,实现浏览器默认样式的统一和重置,可能会更倾向于 normalize.css
一点。
Elements
同样跟 SMACSS 的 Base 层比较相似,对元素(例如form表单、input等)的样式进行一些定制化的设置,可能会更倾向于 reset.css
一点。
Objects
这里就有一点像 OOCSS 中的 容器 和 结构 两个概念。
Components
特定的 UI 组件,大部分的工作将会在这里进行,同时 Components 本身其实和 OOCSS 中的 内容 和 风格 两个概念较为差不太多,通常需要和 Objects 结合使用。
Utilities
权重最高 的样式,用于覆盖其他层中的样式。
ACSS
ACSS 算是目前 CSS 开发模式中比较知名和火热的了,很多大型公司的网站应用都用了 ACSS 方案的,当然 ACSS 之所以能大火也是因为 组件化 的开发方式普及。
ACSS 是 Atomic CSS
的简写,翻译过来就是 原子化 CSS ,ACSS 倾向于使用 小巧且单一 的 className ,并且会以比较 直观(css 缩写) 的的形式进行命名,例如 .p10 .pl10 .pr10 .fl .red
等。
ACSS 拥有 极致的可复用性,但是也 丢失了 className 的语义化能力。
CSS 架构的因地制宜
现在应该都对 CSS 架构 有了 初步 的了解了,但是这五种方案其实都 不一定能完全满足 所有项目中的场景,所以就需要 灵活的进行调整。
基准方案 是使用 ITCSS 搭配 OOCSS 和 BEMCSS 的规范,并且对分层进行调整:
- Settings 和 Tools 层是需要保留的,不管使不使用 CSS 的预处理器,这两层的都是很必要的;
- Generic 和 Elements 可以合并成一个 Base 层,来对各个浏览器的 HTML 元素默认样式进行统一、重置以及定制;
- Objects 和 Components 可以被
Vue、React
中的 组件 给 替代 掉,不再需要单独创建层来进行管理和维护了,当然也可以说是把 Objects 和 Components 合并成一个层,但是这个层 只存在架构图中,在项目中没有其特定的管理目录或文件,因为所有的Vue、React
组件都是,同时这一层统一约定 使用 BEMCSS 的规范进行约束; - Theme 需要新增皮肤的一个层级,主题皮肤在现在的项目中,基本上都是标配了,当然如果没有也可以不需要这一层;
- Utilities 这一层可以考虑和 ACSS 进行结合使用,定制一些项目中特别常用的单项的 className 出来进行复用。
当然,这也只是一种可能,我们可以在 github
上查看一些成熟的 UI 组件库 CSS 部分的源代码,结合现在对 CSS 架构的理解,很容易的就可以对它们 CSS 如何架构和分层进行学习和参考,就拿 Ant Design Vue
来举个栗子:
Ant Design Vue
把颜色的变量和处理工具独立出来放到了 color
文件夹中,并且把主题和变量合并成了一个放到了 themes
文件夹(一个主题对应一份变量文件),mixins
自然是工具了,core
则是对浏览器样式的统一、重置和定制而且还附带了动画相关的内容。(个人理解,如果有理解上的不同或误差欢迎沟通和指正)
总结
CSS 的痛有点难受,你说不管它吧,它时不时的蹦出来让你痛的难受;你说你管它吧,费时费力还不一定能讨个好(绩效),而且一般中小型和非长期维护的项目里面说真的还真不一定非要用到这玩意儿,毕竟是有学习成本和使用成本在里面的,但是中大型项目和长期维护的项目里对 CSS 进行架构设计也绝对是物超所值的一件事!
说起来 CSS 架构这玩意儿覆盖面可能还不太广,我也是因为很久之前的一个面试,才知道 CSS 还有设计模式的(虽然面完后也没有过多的去了解)。
转载自:https://juejin.cn/post/7193514569552101432