在参与规模庞大、历时漫长且人手众多的项目时,所有开发者遵守如下规则极为重要:
+ **保持 CSS 的可维护性**
+ **保持代码清晰易懂**
+ **保持代码的可拓展性**
为了实现这一目标,我们要采用诸多方法。
本文档第一部分将探讨语法、格式以及 CSS 分析;第二部分将从方法论、思维框架以及编写与规划 CSS 的态度入手。
## 目录
* CSS 文档分析
* 总览
* 单一文件与多文件
* 目录
* 章节标题
* 代码顺序
* 规则解析
* 命名规范
* I18n
* 注释
* 注释的拓展用法
* 准修饰选择器
* 代码标签
* 继承标记
* 编写 CSS
* 添加新部分
* 面向对象 CSS
* 布局
* 界面尺寸
* 字号调节
* 简写
* IDs
* 选择器
* 过修饰选择器
* 选择器性能
* 选择器继承
* `!important`
* 魔数与绝对比例
* 条件判断
* Debugging
* 预处理
---
## CSS 文档分析
无论编写什么文档,我们都应当尽力维持统一的风格,包括统一的注释、统一的语法与统一的命名规范。
### 总则
尽量将行宽控制在 80 字节以下。渐变(gradient)相关的语法以及注释中的 URL 等可以算作例外,毕竟这部分我们也无能为力。
我倾向于用 4 个空格而非 Tab 缩进,并且将声明拆分成多行。
### 单一文件与多文件
有些人喜欢将样式写成一个大文件,这并不赖,而且如果你按照下文的规则来编写的话也不会遇到什么问题。我在迁移至 Sass 之后,开始将样式拆分成众多小文件。这也不赖。无论你采用什么方式,下文中的规则都将适用。这两种写法仅仅在目录以及区块标题上有所差异。
### 目录
在 CSS 的开头,我会写一份目录,例如:
/*------------------------------------*/
$CONTENTS
/*------------------------------------*/
/**
* CONTENTS............You’re reading it!
* RESET...............Set our reset defaults
* FONT-FACE...........Import brand font files
*/
这份目录可以告诉其他开发者这个文件中具体含有哪些内容。这份目录中的每一项都与其对应的区块标题相同。
如果你在维护一份规模较大的单文件 CSS,对应的区块将也在同一文件中。如果你是在编写一组小文件,那么目录中的每一项应当对应相应的 @include 语句。
### 区块标题
目录应当对应区块的标题。请看如下示例:
/*------------------------------------*/
$RESET
/*------------------------------------*/
区块标题前缀 `$` 可以让我们使用([Cmd|Ctrl]+F)命令查找 `$[SECTION-NAME]`,同时 **将搜索范围限制在区块标题中**。
如果你在维护一份大文件,那么在区块之间空 5 行,如下:
/*------------------------------------*/
$RESET
/*------------------------------------*/
[Our
reset
styles]
/*------------------------------------*/
$FONT-FACE
/*------------------------------------*/
在大文件中快速翻动时这些大块的空档有助于区分区块。
如果你在维护多份、以 @include 连接的 CSS 的话,在每份文件头加上标题即可,不必这样空行。
## 顺序
尽量按照特定顺序编写规则,这将确保你充分发挥 CSS 缩写中第一个 <i>C</i> 的意义:cascade,层叠。
一份规划良好的 CSS 应当按照如下排列:
1. **Reset** 万物之根源
2. **元素类型** 没有设置 class 的 `h1`、`ul` 等
3. **对象以及抽象内容** 最一般、最基础的设计模式
4. **子元素** 由对象延伸出来的所有拓展及其子元素
5. **修补** 针对异常状态
如此一来,当你依次编写 CSS 时,每个区块都可以自动继承在它之前区块的属性。这样就可以减少代码相互抵消的部分,减少某些特殊的问题,构成设计更理想的 CSS 结构。
关于这方面的更多信息,强烈推荐 Jonathan Snook 的 [SMACSS](http://smacss.com)。
## CSS 规则集分析
[selector]{
[PRoperty]:[value];
[<- Declaration ->]
}
[选择器]{
[属性]:[值];
[<- 声明 ->]
}
编写 CSS 样式时,我习惯遵守这些规则:
* class 名称以连字符(-)连接,除了下文提到的 BEM 命名法;
* 缩进 4 空格;
* 声明拆分成多行;
* 声明以相关性顺序排列,而非字母顺序;
* 有前缀的声明适当缩进,对齐其值;
* 缩进样式从而反映 DOM;
* 保留最后一条声明结尾的分号。
例如:
.widget{
padding:10px;
border:1px solid #BADA55;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
}
.widget-heading{
font-size:1.5rem;
line-height:1;
font-weight:bold;
color:#BADA55;
margin-right:-10px;
margin-left: -10px;
padding:0.25em;
}
我们可以发现,`.widget-heading` 是 `.widget` 的子元素,因为前者比后者多缩进了一级。这使得开发者在阅读这些样式时可以快速获取信息。
我们还可以发现 `.widget-heading` 的声明是根据其相关性排列的:`.widget-heading` 是文字元素,所以我们先添加字体相关的样式声明,接下来是其它的。
以下是一个没有拆分成多行的例子:
.t10 { width:10% }
.t20 { width:20% }
.t25 { width:25% } /* 1/4 */
.t30 { width:30% }
.t33 { width:33.333% } /* 1/3 */
.t40 { width:40% }
.t50 { width:50% } /* 1/2 */
.t60 { width:60% }
.t66 { width:66.666% } /* 2/3 */
.t70 { width:70% }
.t75 { width:75% } /* 3/4*/
.t80 { width:80% }
.t90 { width:90% }
在这个例子(来自[inuit.css’s table grid system](https://github.com/csswizardry/inuit.css/blob/master/inuit.css/partials/base/_tables.scss#L88))中,将 CSS 放在一行内可以使得代码更紧凑。
## 命名规范
一般情况下我都是以连字符(-)连接 class 的名字(例如 `.foo-bar` 而非 `.foo_bar` 或 `.fooBar`),不过在某些特定的时候我会用 BEM(Block, Element, Modifier)命名法。
<abbr title="Block, Element, Modifier">BEM</abbr> 命名法可以使得选择器更规范,更清晰,更具语义。
该命名法按照如下格式:
.block{}
.block__element{}
.block--modifier{}
其中:
* `.block` 代表某个基本的抽象元素;
* `.block__element` 代表 `.block` 这一整体的一个子元素;
* `.block--modifier` 代表 `.block` 的某个不同状态。
打个比方:
.person{}
.person--woman{}
.person__hand{}
.person__hand--left{}
.person__hand--right{}
这个例子中我们描述的最基本元素是一个人,然后这个人可能是一个女人。我们还知道人拥有手,这些是人体的一部分,而手也有不同的状态,如同左手与右手。
这样我们就可以根据亲元素来规定选择器的命名空间并传达该选择器的职能,它是一个子元素(`__`)还是不同状态(`--`)?
由此,`.page-wrapper` 是一个独立的选择器。这是一个符合规范的命名,因为它不是其它元素的子元素或其它状态;然而 `.widget-heading` 则与其它对象有关联,它应当是 `.widget` 的子元素,所以我们应当将其重命名为 `.widget__heading`。
BEM 命名法虽然不太好看,而且相当冗长,但是它使得我们可以通过名称快速获知元素的功能和元素之间的关系。与此同时,BEM 语法中的重复部分非常有利于 gzip 的压缩算法。
无论你是否使用 BEM 命名法,你都应当确保 class 命名得当,力保一字不多、一字不少;将元素命名抽象化以提高复用性(例如 `.ui-list`,`.media`)。由此延伸出去的元素命名则要尽量精准(例如 `.user-avatar-link`)。不用担心 class 名的数量或长度,因为写得好的代码 gzip 也能有效压缩。
### HTML 中的 class
为了确保易读性,在 HTML 标记中用两个空格隔开 class 名,例如:
<div class="foo--bar bar__baz">
增加的空格应当可以使得在使用多个 class 时更易阅读与定位。
### JS 钩子
**千万不要把 CSS 样式用作 Javascript 钩子。**把 JS 行为与样式混在一起将无法对其分别处理。
如果你要把 JS 和某些标记绑定起来的话,写一个 JS 专用的 class。简单地说就是划定一个前缀 `.js-` 的命名空间,例如 `.js-toggle`,`.js-drag-and-drop`。这意味着我们可以通过 class 同时绑定 JS 和 CSS 而不会因为冲突而引发麻烦。
<th class="is-sortable js-is-sortable">
</th>
上面的这个标记有两个 class,你可以用其中一个来给这个可排序的表格栏添加样式,用另一个添加排序功能。
### I18n
虽然我(该 CSS Guideline 文档原作者 Harry Roberts)是个英国人,而且我一向拼写 <i>colour</i> 而非 <i>color</i>,但是为了统一性,我认为在 CSS 中用美式拼法更佳。CSS 以及其它多数语言都是以美式拼法编写,所以如果在 `.colour-picker{}` 中写 `color:red` 就缺乏统一性。我以前主张同时用两种拼法,例如:
.color-picker,
.colour-picker{
}
但是我最近参与了一份规模庞大的 Sass 项目,这个项目中有许多的颜色变量(例如 `$brand-color`,`$highlight-color` 等等),每个变量要维护两种拼法实在辛苦,要查找并替换时也需要两倍的工作量。
所以为了统一性,把所有的 class 与变量都以你参与的项目的惯用拼法命名即可。
## 注释
我使用行宽不超过 80 字节的块状注释:
/**
* This is a docBlock style comment
*
* This is a longer description of the comment, describing the code in more
* detail. We limit these lines to a maximum of 80 characters in length.
*
* We can have markup in the comments, and are encouraged to do so:
*
<div class="foo">
<p>Lorem</p>
</div>
*
* We do not prefix lines of code with an asterisk as to do so would inhibit
* copy and paste.
*/
/**
* 这是一个文档块(DocBlock)风格的注释。
*
* 这里开始是描述更详细、篇幅更长的注释正文。当然,我们要把行宽控制在 80 字以内。
*
* 我们可以在注释中嵌入 HTML 标记,而且这也是个不错的办法:
*
<div class="foo">
<p>Lorem</p>
</div>
*
* 如果是注释内嵌的标记的话,在它前面不加星号,否则会被复制进去。
*/
在注释中应当尽量详细描述代码,因为对你来说清晰易懂的内容对其他人可能并非如此。每写一部分代码就要专门写注释以详解。
### 注释的拓展用法
注释有许多很先进的用法,例如:
* 准修饰选择器
* 代码标签
* 继承标记
#### 准修饰选择器
你应当避免过分修饰选择器,例如如果你能写 `.nav{}` 就尽量不要写 `u
新闻热点
疑难解答