目录
引子
想起刚工作不久的时候,自己想要明确一套规范,而不只是看到什么就是什么,但实际经验欠缺,就只是简单的了解了一下。现在又有这样的念头了,也有对应的素材,尝试着总结一下,看下能弄出什么样来。
CSS 方法论
谈到 CSS 就离不开 HTML,现在有不少关于阐释 HTML 和 CSS 之间关系的理论。了解这些,对于组织 CSS 很有帮助。下面通过网上的一些资料,介绍一些认可度比较高的方法论。
OOCSS 方法
全称是 Object-Oriented CSS,面向对象的 CSS。在 2008 年的时候就被提出,在 OOCSS wiki 介绍中,该方法有两个主要的原则:
1 分离结构和外观
意思是将视觉特性定义为可复用的单元(例如背景和边框样式)。换句话说,就是把布局和设计的样式都独立出来。见下面的例子:
<div class="warn">warning</div>
样式 warn 表示警告的字体颜色,在系统内,只要是用到警告的地方,统一使用这个样式。
2 分离容器和内容
意思是指把内容从容器中分离开来。不论你放到那里,看起来都是一样的。见下面的例子:
<div class="dialog blue">
<div class=“dialog-title”><span class="text">Title</span></div>
<div class="dialog-content show"><span class="text">content</span></div>
</div>
这个例子中不同的模块显示不同的字体和颜色,一般可能会这样做:
.dialog-title .text {color: #333;}
.dialog-content .text {color: #666;}
但在 OOCSS 方法中是通过添加一个新的 class
来描述需要的样式:
<div class="dialog blue">
<div class=“dialog-title”><span class="text title-text">Title</span></div>
<div class="dialog-content show"><span class="text content-text">content</span></div>
</div>
.title-text {color: #333;}
.content-text {color: #666;}
当想提供一套组件让开发人员组合起来创建用户界面时,这种方法非常有用。Bootstrap 就是一个例子,它是一个自带各种皮肤的小组件系统。
SMACSS 方法
全称是 Scalable and Modular Architecture for CSS,模块化架构的可扩展 CSS。SMACSS 把样式系统划分为五个具体类别:
- 基础:标签默认展示的样式,基本上就是元素选择器,可以包含属性选择器、伪类选择器、子选择器或兄弟选择器。在这个里面不应该出现
!important
。 - 布局:把页面分成一些区域。
- 模块:设计中的模块化、可复用的单元,例如列表、弹窗等。
- 状态:描述在特定的状态或情况下,模块或布局的显示方式。
- 主题:一个可选的视觉外观层,可以让你更换不同主题。
见下面的例子:
<div class="dialog dialog-blue">
<div class=“dialog-title”><span class="text">Title</span></div>
<div class="dialog-content is-show"><span class="text">content</span></div>
</div>
观察模块样式 dialog
、dialog-blue
、dialog-title
、dialog-content
和状态 is-show
,可以发现对于如何创建功能的小模块,OOCSS 和 SMACSS 有许多相似之处。它们都把样式作用域限定到根节点的 CSS 类名上,然后通过皮肤(OOCSS)或者子模块(SMACSS)进行修改。除了SMACSS 把代码划分类别之外,两者之间最显著的差异是使用皮肤而不是子模块,以及带 is
前缀的状态类名。
BEM 方法
全称是 Block Element Modifier,块元素修饰符。BEM 是一种基于组件的 Web 开发方法。其背后的想法是将用户界面划分为独立的块。其中包含的内容不仅仅是 CSS,其中 CSS 的内容结合 About HTML semantics and front-end architecture,得出一套命名规则:
- 块名:所属组件的名称,一般形式为
.block
。 - 元素:元素在块里面的名称,一般形式为
.block__element
。 - 修饰符:任何与块或元素相关联的修饰符,一般形式为
.block--modifier
。
看下面例子:
<div class="dialog dialog-skin-blue">
<div class=“dialog__title”><span class="dialog__text">Title</span></div>
<div class="dialog__content dialog__content--show"><span class="dialog__text">content</span></div>
</div>
这种方式不建议使用元素选择器,名称过长时,用 - 连接。BEM 使用非常简洁的约定来创建 CSS 类名,而这些字符串可能会相当长。
这种方法在 OOCSS 或 SMACSS 里使用的好处是,每一个 CSS 类名都详细地描述了它实现了什么。代码中没有 show
或者 is-show
这样只在特定背景下才能理解的 CSS 类名。如果单独看 show
或者 is-show
这两个名字,我们并不知道它们的含义是什么。
虽然 BEM 法看起来很累赘、很冗余 ,但是当看到一个 dialog__content--show
的 CSS 类名,就知道它是表示:这个元素的名称是 content,位置在 dialog 组件里,状态为显示。
关于方法的选择
没有什么方法论是完美的,你可能会发现,不同的项目适合不同的方法。也许还有新的方法,我们还没有发现,不要因为一套规范很流行或者别的团队在使用就选择它。理解方案背后这么做的原因,不要害怕尝试,混合已有的方案,甚至自己或者团队一起创造出独一无二的方案。
规范
原则
- 删除僵尸代码。
- 不能有行内 CSS。
- 不能有空的规则。
- 选择器不能超过 3 层。
- 一个标签上的类名不能超过 4 个,给 js 使用的类名不算。
- 若无 ID 可用,给 js 使用的类样式必须带 js 前缀,且不能有具体样式。
- 删除冗余 ID,避免使用 ID 选择器,如果有,转换为类选择器。
- 给出必要的注释说明。
- 抽离基础样式和功能性样式,并提供注释说明,对团队告知对应位置。
- 避免使用
!important
。
由于 CSS 选择符是从右到左进行匹配,所以:
- 避免使用标签,例如
.content ul li
。 - 避免使用通配符。
- 避免使用子选择符,例如
.content > ul >li
。
命名
- 根据选择的方法,与团队成员共同商定命名形式,可能涉及到公用样式、组件样式、对应页面样式。
- 类名使用小写。
- ID 采用驼峰式命名。
代码风格
缩进
使用 2 个空格。
空格
需要空格情况:
{
前。- 冒号
:
后面。 !important
前。- 注释的开始和结尾。
不需要空格情况:
- 冒号
:
前面。 !important
中!
后。- 多个规则的分隔符
,
前。 - 属性值中
(
后和)
前。
/* good */
.nav,
.footer {
font-size: 18px;
color: #666 !important;
background-color: rgba(0,0,0,.5);
}
/*not good*/
.nav ,
.footer{
font-size :18px;
color: #666! important;
background-color: rgba( 0, 0, 0, .5 );
}
空行
需要空行的情况:
- 文件最后保留一个空行。
}
后留空行.
/* good */
.nav {
font-size: 18px;
}
.footer {
color: #666;
}
/* not good */
.nav {
font-size: 18px;
}
.footer {
color: #666;
}
换行
需要换行的情况:
{
后和}
前。- 每个属性及对应值独占一行。
- 多个规则的分隔符
,
后。
/* good */
.nav,
.footer {
font-size: 18px;
color: #666;
}
.body {
font-size: 16px;
}
/* not good */
.nav,.footer {
font-size: 18px;color: #666;
}
.body {font-size: 16px;}
分号
每个属性名末尾要加分号。
/* good */
.nav {
font-size: 18px;
}
/* not good */
.nav {
font-size: 18px
}
引号
统一使用双引号。
/* good */
.nav:before {
content: "";
font-size: 18px;
}
/* not good */
.nav:before {
content: '';
font-size: 18px;
}
颜色
使用小写字幕,能简写就使用简写。
/* good */
.nav {
color: #ab1243;
background-color: #236;
}
/* not good */
.nav {
color: #AB1243;
background-color: #223366;
}
属性值为 0 的情况
- 不要带单位。
- 在定义无边框样式时,使用 0 代替 none。
- 去除小数点前面的 0。
属性简写
需要简写的属性有:
- margin。
- padding。
/* good */
.nav {
margin: 10px 0 0 6px;
padding: 2px 0 0 3px;
}
/* not good */
.nav {
margin-top: 10px;
margin-left: 6px;
padding-top: 2px;
padding-left: 3px;
}
属性声明顺序
建议顺序为:
- 布局定位属性。
[
"display",
"visibility",
"float",
"clear",
"overflow",
"clip",
"zoom",
"table-layout",
"border-spacing",
"border-collapse",
"list-style",
"flex",
"flex-direction",
"justify-content",
"align-items",
"position",
"top",
"right",
"bottom",
"right",
"z-index",
]
- 自身属性。
[
"margin",
"box-sizing",
"border",
"border-radius",
"padding",
"width",
"min-width",
"max-widht",
"height",
"min-height",
"max-height",
]
- 文本属性。
[
"font-size",
"line-height",
"text-align",
"vertical-align",
"white-space",
"text-decoration",
"text-emphasis",
"text-indent",
"text-overflow",
"word-wrap",
"word-break",
"color",
"text-shadow",
]
- 其它属性。
[
"background",
"background-color",
"background-image",
"background-repeat",
"background-attachment",
"background-position",
"background-clip",
"background-origin",
"background-size",
"outline",
"opacity",
"filter",
"box-shadow",
"transition"
"transform",
"animation",
"cursor",
"pointer-events",
]
媒体查询
尽量将媒体查询的规则靠近与他们相关的规则,不要将他们一起放到一个独立的样式文件中,或者丢在文档的最底部,这样做只会让大家以后更容易忘记他们。
/* good */
.nav {
font-size: 14px;
}
@media (min- 480px) {
.nav {
font-size: 16px;
}
}
对比 stylelint
recommended 配置
对比 stylelint-config-recommended 配置中的规则,发现:
- 可能的错误中,大部分一般是比较少碰到,有的碰到也是比较好发现,因为在页面展示上很容易体现出来。
- 去重方面可以减少不必要的代码。
- 检查有效的源码和注释,可以减少冗余。
standard 配置
在 stylelint-config-standard 配置中的规则,发现:
- 空行、空格、换行在格式上情况更多。
- 区分了单行和多行的情况。
- 函数、选择器、媒体查询需要单独处理。
规范 stylelint 化
基于 stylelint-config-recommended
配置,根据 stylelint 已有的配置规则,以及上面总结的规范进行自选配置。
"use strict"
module.exports = {
"extends": "stylelint-config-recommended",
"rules": {
// 缩进
"indentation": 2,
// 空格
"block-opening-brace-space-before": "always",
"declaration-colon-space-after": "always",
"declaration-bang-space-before": "always",
"comment-whitespace-inside": "always",
"declaration-colon-space-before": "never",
"declaration-bang-space-after": "never",
"value-list-comma-newline-before": "never",
// 空行
"max-empty-lines": 1,
// 换行
"block-closing-brace-newline-after": "always",
"block-opening-brace-newline-after": "always",
"declaration-block-semicolon-newline-after": "always",
"selector-list-comma-newline-after": "always",
// 引号
"string-quotes": "double",
// 颜色
"color-hex-length": "short",
"color-hex-case": "lower",
},
}
相关示例和工具
在收集资料过程中碰到的示例和工具,有些需要翻墙。
示例
- 评估复杂选择符和简单选择符的开销 CSS Selector Tests
工具
- 回流计时器
- 性能的分析器 YSlow、AOL WebPageTest
- 分析和优化网页中图片服务 Smush.it
- 样式文档工具 hologram