We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文档的目标是使 CSS 代码风格保持一致,容易被理解和被维护。
虽然本文档是针对 CSS 设计的,但是在使用各种 CSS 的预编译器(如 less、sass、stylus 等)时,适用的部分也应尽量遵循本文档的约定。
less、sass、stylus
[建议] CSS 文件使用无 BOM 的 UTF-8 编码。
CSS长短命名争论由来已久。宽松的CSS命名将导致团队成员各起炉灶,各种命名混在项目中理也理不清。
我们更倾向于长命名,并采用BEM(Block Element Modifier)命名方法。应用这种命名方法一来很容易理解组件之间的联系,二来能避免命名空间冲突。
我们可以把页面任意区域划分为独立模块,代表更高级别的抽象或组件。一个header是block,里面的搜索框也是block,甚至是logo也是。
block可以嵌套。
.block__element 代表.block的后代,用于形成一个完整的.block的整体。一个Block下的所有Element无论相互层级如何,都要摊开扁平的属于Block。所以 BEM 最多只有 B+E+M 三级,不可能出现 B+E+E+..+E+M 超长class名,也要求E不能同名。
代表.block的不同状态或不同版本。比如之前我们经常写的 .current .active 等。
我们约定:
__双下划线代表B和E连接,例如:menu__item
menu__item
_单下划线代表B和M或E和M的连接,例如:menu_active 或 menu__item_active
menu_active
menu__item_active
-中划线同英语里做连字符,例如:mod-menu 或 mod-menu__item。这里B或E或M需要多个单词来描述,就使用中划线。
mod-menu
mod-menu__item
例子一:
<ul class="menu"> <li class="menu__item">Index</li> <li class="menu__item menu__item_state_current">Products</li> <li class="menu__item">Contact</li> </ul>
BEM是不允许用标签选择器的,一开始难以接受....
menu li 能搞定的事情需要每个 li 都写.menu-item
menu li
.menu-item
例子二:
<!-- 常规写法 --> <form class="site-search full"> <input type="text" class="field"> <input type="Submit" value ="Search" class="button"> </form> <!-- BEM写法 --> <form class="site-search site-search--full"> <input type="text" class="site-search__field"> <input type="Submit" value ="Search" class="site-search__button"> </form>
参考:
BEM_入门 精通 教程 如何看待 CSS 中 BEM 的命名方式?
[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。
示例:
.selector { margin: 0; padding: 0; }
[强制] 选择器 与 { 之间必须包含空格。
.selector { }
[强制] 属性名 与之后的 : 之间不允许包含空格, : 与 属性值 之间必须包含空格。
margin: 0;
[强制] 列表型属性值 书写在单行时,, 后必须跟一个空格。
font-family: Arial, sans-serif;
[建议] 对于超长的样式,在样式值的 空格 处或 , 后换行,建议按逻辑分组。
/* 不同属性值按逻辑分组 */ background: transparent url(aVeryVeryVeryLongUrlIsPlacedHere) no-repeat 0 0; /* 可重复多次的属性,每次重复一行 */ background-image: url(aVeryVeryVeryLongUrlIsPlacedHere) url(anotherVeryVeryVeryLongUrlIsPlacedHere); /* 类似函数的属性值可以根据函数调用的缩进进行 */ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.04, rgb(88,94,124)), color-stop(0.52, rgb(115,123,162)) );
[强制] 当一个 rule 包含多个 selector 时,每个选择器声明必须独占一行。
/* good */ .post, .page, .comment { line-height: 1.5; } /* bad */ .post, .page, .comment { line-height: 1.5; }
[强制] >、+、~ 选择器的两边各保留一个空格。
/* good */ main > nav { padding: 10px; } label + input { margin-left: 5px; } input:checked ~ button { background-color: #69C; } /* bad */ main>nav { padding: 10px; } label+input { margin-left: 5px; } input:checked~button { background-color: #69C; }
[强制] 属性选择器中的值必须用双引号包围。
解释:
不允许使用单引号,不允许不使用引号。
/* good */ article[character="juliet"] { voice-family: "Vivien Leigh", victoria, female; } /* bad */ article[character='juliet'] { voice-family: "Vivien Leigh", victoria, female; }
[强制] 属性定义必须另起一行。
/* good */ .selector { margin: 0; padding: 0; } /* bad */ .selector { margin: 0; padding: 0; }
[强制] 属性定义后必须以分号结尾。
/* good */ .selector { margin: 0; } /* bad */ .selector { margin: 0 }
[强制] 如无必要,不得为 id、class 选择器添加类型选择器进行限定。
id
class
在性能和维护性上,都有一定的影响。
/* good */ #error, .danger-message { font-color: #c00; } /* bad */ dialog#error, p.danger-message { font-color: #c00; }
[建议] 选择器的嵌套层级应不大于 3 级,位置靠后的限定条件应尽可能精确。
解析:
嵌套层级越多,CSS 权重越大。我们应该书写权重小的 CSS 代码。
/* good */ #username input {} .comment .avatar {} /* bad */ .page .header .login #username input {} .comment div * {}
[建议] 在可以使用缩写的情况下,尽量使用属性缩写。
/* good */ .post { font: 12px/1.5 arial, sans-serif; } /* bad */ .post { font-family: arial, sans-serif; font-size: 12px; line-height: 1.5; }
[建议] 使用 border / margin / padding 等缩写时,应注意隐含值对实际数值的影响,确实需要设置多个方向的值时才使用缩写。
border / margin / padding 等缩写会同时设置多个属性的值,容易覆盖不需要覆盖的设定。如某些方向需要继承其他声明的值,则应该分开设置。
border / margin / padding
/* centering <article class="page"> horizontally and highlight featured ones */ article { margin: 5px; border: 1px solid #999; } /* good */ .page { margin-right: auto; margin-left: auto; } .featured { border-color: #69c; } /* bad */ .page { margin: 5px auto; /* introducing redundancy */ } .featured { border: 1px solid #69c; /* introducing redundancy */ }
[建议] 同一 rule set 下的属性在书写时,应按功能进行分组,并以 Formatting Model(布局方式、位置) > Box Model(尺寸) > Typographic(文本相关) > Visual(视觉效果) 的顺序书写,以提高代码的可读性。
position / top / right / bottom / left / float / display / overflow
border / margin / padding / width / height
font / line-height / text-align / word-wrap
background / color / transition / list-style
content
.sidebar { /* formatting model: positioning schemes / offsets / z-indexes / display / ... */ position: absolute; top: 50px; left: 0; overflow-x: hidden; /* box model: sizes / margins / paddings / borders / ... */ width: 200px; padding: 5px; border: 1px solid #ddd; /* typographic: font / aligns / text styles / ... */ font-size: 14px; line-height: 20px; /* visual: colors / shadows / gradients / ... */ background: #f5f5f5; color: #333; -webkit-transition: color 1s; -moz-transition: color 1s; transition: color 1s; }
[建议] 当元素需要撑起高度以包含内部的浮动元素时,通过对伪类设置 clear 或触发 BFC 的方式进行 clearfix。尽量不使用增加空标签的方式。
clear
clearfix
触发 BFC 的方式很多,常见的有:
float
none
position
static
overflow
visible
如希望使用更小副作用的清除浮动方法,参见 A new micro clearfix hack 一文。
另需注意,对已经触发 BFC 的元素不需要再进行 clearfix。
[建议] 尽量不使用 !important 声明。
[强制] 文本内容必须用双引号包围。
文本类型的内容可能在选择器、属性值等内容中。
/* good */ html[lang|="zh"] q:before { font-family: "Microsoft YaHei", sans-serif; content: "“"; } html[lang|="zh"] q:after { font-family: "Microsoft YaHei", sans-serif; content: "”"; } /* bad */ html[lang|=zh] q:before { font-family: 'Microsoft YaHei', sans-serif; content: '“'; } html[lang|=zh] q:after { font-family: "Microsoft YaHei", sans-serif; content: "”"; }
[强制] 当数值为 0 - 1 之间的小数时,省略整数部分的 0。
/* good */ panel { opacity: .8; } /* bad */ panel { opacity: 0.8; }
[强制] url() 函数中的路径不加引号。
url()
body { background: url(bg.png); }
[建议] url() 函数中的绝对路径可省去协议名。
body { background: url(//baidu.com/img/bg.png) no-repeat 0 0; }
[强制] 长度为 0 时须省略单位。 (也只有长度单位可省)
/* good */ body { padding: 0 5px; } /* bad */ body { padding: 0px 5px; }
[强制] RGB颜色值必须使用十六进制记号形式 #rrggbb。不允许使用 rgb()。
#rrggbb
rgb()
带有alpha的颜色信息可以使用 rgba()。使用 rgba() 时每个逗号后必须保留一个空格。
rgba()
/* good */ .success { box-shadow: 0 0 2px rgba(0, 128, 0, .3); border-color: #008000; } /* bad */ .success { box-shadow: 0 0 2px rgba(0,128,0,.3); border-color: rgb(0, 128, 0); }
[强制] 颜色值可以缩写时,必须使用缩写形式。
/* good */ .success { background-color: #aca; } /* bad */ .success { background-color: #aaccaa; }
[强制] 颜色值不允许使用命名色值。
/* good */ .success { color: #90ee90; } /* bad */ .success { color: lightgreen; }
[建议] 颜色值中的英文字符采用小写。如不用小写也需要保证同一项目内保持大小写一致。
/* good */ .success { background-color: #aca; color: #90ee90; } /* good */ .success { background-color: #ACA; color: #90EE90; } /* bad */ .success { background-color: #ACA; color: #90ee90; }
[强制] font-family 属性中的字体族名称应使用字体的英文 Family Name,其中如有空格,须放置在引号中。
所谓英文 Family Name,为字体文件的一个元数据,常见名称如下:
[强制] font-family 按「西文字体在前、中文字体在后」、「效果佳 (质量高/更能满足需求) 的字体在前、效果一般的字体在后」的顺序编写,最后必须指定一个通用字体族( serif / sans-serif )。
font-family
serif
sans-serif
更详细说明可参考本文。
/* Display according to platform */ .article { font-family: Arial, sans-serif; } /* Specific for most platforms */ h1 { font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft YaHei", sans-serif; }
[强制] font-family 不区分大小写,但在同一个项目中,同样的 Family Name 大小写必须统一。
/* good */ body { font-family: Arial, sans-serif; } h1 { font-family: Arial, "Microsoft YaHei", sans-serif; } /* bad */ body { font-family: arial, sans-serif; } h1 { font-family: Arial, "Microsoft YaHei", sans-serif; }
[强制] 需要在 Windows 平台显示的中文内容,其字号应不小于 12px。
由于 Windows 的字体渲染机制,小于 12px 的文字显示效果极差、难以辨认。
[强制] Media Query 不得单独编排,必须与相关的规则一起定义。
/* Good */ /* header styles */ @media (...) { /* header styles */ } /* main styles */ @media (...) { /* main styles */ } /* footer styles */ @media (...) { /* footer styles */ } /* Bad */ /* header styles */ /* main styles */ /* footer styles */ @media (...) { /* header styles */ /* main styles */ /* footer styles */ }
[强制] 带私有前缀的属性由长到短排列,按冒号位置对齐。
标准属性放在最后,按冒号对齐方便阅读,也便于在编辑器内进行多行编辑。
.box { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
[建议] 需要添加 hack 时应尽可能考虑是否可以采用其他方式解决。
如果能通过合理的 HTML 结构或使用其他的 CSS 定义达到理想的样式,则不应该使用 hack 手段解决问题。通常 hack 会导致维护成本的增加。
[建议] 尽量使用 选择器 hack 处理兼容性,而非 属性 hack。
尽量使用符合 CSS 语法的 selector hack,可以避免一些第三方库无法识别 hack 语法的问题。
/* IE 7 */ *:first-child + html #header { margin-top: 3px; padding: 5px; } /* IE 6 */ * html #header { margin-top: 5px; padding: 4px; }
[建议] 尽量使用简单的 属性 hack。
.box { _display: inline; /* fix double margin */ float: left; margin-left: 20px; } .container { overflow: hidden; *zoom: 1; /* triggering hasLayout */ }
8.3 Expression
[强制] 禁止使用 Expression。
前面提及的BEM命名法目的之一就是使前端开发偏向模块化发展。按照Block级别把CSS文件拆分为不同的模块。下图作为参考(图片来源于知乎):
从图中,我们至少分析到几点:
CSS代码根据其职能需要进行分层。(假设应用了预编译语言)
第一层,var或util层(瞎起的😂)。里面保存了sass全局变量、函数、minx等。
第一层,base层。包含CSS Reset和global CSS。
第三层,page层。可以按照上面所拆分的Block进行组织。
通过统一命名前缀可以保证文件按主要功能排列。如import-lib、import-module等等。
import-lib
import-module
通过import语句进行CSS模块的引用。
import
我们运用Less和Sass。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
1 说明
本文档的目标是使 CSS 代码风格保持一致,容易被理解和被维护。
虽然本文档是针对 CSS 设计的,但是在使用各种 CSS 的预编译器(如
less、sass、stylus
等)时,适用的部分也应尽量遵循本文档的约定。2 代码风格
2.1 文件
[建议] CSS 文件使用无 BOM 的 UTF-8 编码。
2.2 命名规范
CSS长短命名争论由来已久。宽松的CSS命名将导致团队成员各起炉灶,各种命名混在项目中理也理不清。
我们更倾向于长命名,并采用BEM(Block Element Modifier)命名方法。应用这种命名方法一来很容易理解组件之间的联系,二来能避免命名空间冲突。
我们可以把页面任意区域划分为独立模块,代表更高级别的抽象或组件。一个header是block,里面的搜索框也是block,甚至是logo也是。
block可以嵌套。
.block__element 代表.block的后代,用于形成一个完整的.block的整体。一个Block下的所有Element无论相互层级如何,都要摊开扁平的属于Block。所以 BEM 最多只有 B+E+M 三级,不可能出现 B+E+E+..+E+M 超长class名,也要求E不能同名。
代表.block的不同状态或不同版本。比如之前我们经常写的 .current .active 等。
我们约定:
__双下划线代表B和E连接,例如:
menu__item
_单下划线代表B和M或E和M的连接,例如:
menu_active
或menu__item_active
-中划线同英语里做连字符,例如:
mod-menu
或mod-menu__item
。这里B或E或M需要多个单词来描述,就使用中划线。例子一:
BEM是不允许用标签选择器的,一开始难以接受....
menu li
能搞定的事情需要每个 li 都写.menu-item
例子二:
参考:
BEM_入门 精通 教程
如何看待 CSS 中 BEM 的命名方式?
2.3 缩进
[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符。
示例:
2.4 空格
[强制] 选择器 与 { 之间必须包含空格。
示例:
[强制] 属性名 与之后的 : 之间不允许包含空格, : 与 属性值 之间必须包含空格。
示例:
[强制] 列表型属性值 书写在单行时,, 后必须跟一个空格。
示例:
2.5 行长度
[建议] 对于超长的样式,在样式值的 空格 处或 , 后换行,建议按逻辑分组。
示例:
2.6 选择器
[强制] 当一个 rule 包含多个 selector 时,每个选择器声明必须独占一行。
示例:
[强制] >、+、~ 选择器的两边各保留一个空格。
示例:
[强制] 属性选择器中的值必须用双引号包围。
解释:
不允许使用单引号,不允许不使用引号。
示例:
2.7 属性
[强制] 属性定义必须另起一行。
示例:
[强制] 属性定义后必须以分号结尾。
示例:
3 通用
3.1 选择器
[强制] 如无必要,不得为
id
、class
选择器添加类型选择器进行限定。解释:
在性能和维护性上,都有一定的影响。
示例:
[建议] 选择器的嵌套层级应不大于 3 级,位置靠后的限定条件应尽可能精确。
解析:
嵌套层级越多,CSS 权重越大。我们应该书写权重小的 CSS 代码。
示例:
3.2 属性缩写
[建议] 在可以使用缩写的情况下,尽量使用属性缩写。
示例:
[建议] 使用 border / margin / padding 等缩写时,应注意隐含值对实际数值的影响,确实需要设置多个方向的值时才使用缩写。
解释:
border / margin / padding
等缩写会同时设置多个属性的值,容易覆盖不需要覆盖的设定。如某些方向需要继承其他声明的值,则应该分开设置。示例:
3.3 属性书写顺序
[建议] 同一 rule set 下的属性在书写时,应按功能进行分组,并以 Formatting Model(布局方式、位置) > Box Model(尺寸) > Typographic(文本相关) > Visual(视觉效果) 的顺序书写,以提高代码的可读性。
解释:
position / top / right / bottom / left / float / display / overflow
等border / margin / padding / width / height
等font / line-height / text-align / word-wrap
等background / color / transition / list-style
等另外,如果包含
content
属性,应放在最前面。示例:
3.4 清除浮动
[建议] 当元素需要撑起高度以包含内部的浮动元素时,通过对伪类设置
clear
或触发 BFC 的方式进行clearfix
。尽量不使用增加空标签的方式。解释:
触发 BFC 的方式很多,常见的有:
float
非none
position
非static
overflow
非visible
如希望使用更小副作用的清除浮动方法,参见 A new micro clearfix hack 一文。
另需注意,对已经触发 BFC 的元素不需要再进行
clearfix
。3.5 !important
[建议] 尽量不使用 !important 声明。
4 值与单位
4.1 文本
[强制] 文本内容必须用双引号包围。
解释:
文本类型的内容可能在选择器、属性值等内容中。
示例:
4.2 数值
[强制] 当数值为 0 - 1 之间的小数时,省略整数部分的 0。
示例:
4.3 url()
[强制]
url()
函数中的路径不加引号。示例:
[建议]
url()
函数中的绝对路径可省去协议名。示例:
4.4 长度
[强制] 长度为 0 时须省略单位。 (也只有长度单位可省)
示例:
4.5 颜色
[强制] RGB颜色值必须使用十六进制记号形式
#rrggbb
。不允许使用rgb()
。解释:
带有alpha的颜色信息可以使用
rgba()
。使用rgba()
时每个逗号后必须保留一个空格。示例:
[强制] 颜色值可以缩写时,必须使用缩写形式。
示例:
[强制] 颜色值不允许使用命名色值。
示例:
[建议] 颜色值中的英文字符采用小写。如不用小写也需要保证同一项目内保持大小写一致。
示例:
5 文本编排
5.1 字体族
[强制] font-family 属性中的字体族名称应使用字体的英文 Family Name,其中如有空格,须放置在引号中。
解释:
所谓英文 Family Name,为字体文件的一个元数据,常见名称如下:
[强制]
font-family
按「西文字体在前、中文字体在后」、「效果佳 (质量高/更能满足需求) 的字体在前、效果一般的字体在后」的顺序编写,最后必须指定一个通用字体族(serif
/sans-serif
)。解释:
更详细说明可参考本文。
示例:
[强制]
font-family
不区分大小写,但在同一个项目中,同样的 Family Name 大小写必须统一。示例:
5.2 字号
[强制] 需要在 Windows 平台显示的中文内容,其字号应不小于 12px。
解释:
由于 Windows 的字体渲染机制,小于 12px 的文字显示效果极差、难以辨认。
6 响应式
[强制] Media Query 不得单独编排,必须与相关的规则一起定义。
示例:
7 兼容性
8.1 属性前缀
[强制] 带私有前缀的属性由长到短排列,按冒号位置对齐。
解释:
标准属性放在最后,按冒号对齐方便阅读,也便于在编辑器内进行多行编辑。
示例:
8.2 Hack
[建议] 需要添加 hack 时应尽可能考虑是否可以采用其他方式解决。
解释:
如果能通过合理的 HTML 结构或使用其他的 CSS 定义达到理想的样式,则不应该使用 hack 手段解决问题。通常 hack 会导致维护成本的增加。
[建议] 尽量使用 选择器 hack 处理兼容性,而非 属性 hack。
解释:
尽量使用符合 CSS 语法的 selector hack,可以避免一些第三方库无法识别 hack 语法的问题。
示例:
[建议] 尽量使用简单的 属性 hack。
示例:
8.3 Expression
[强制] 禁止使用 Expression。
9 CSS文件名和拆分
前面提及的BEM命名法目的之一就是使前端开发偏向模块化发展。按照Block级别把CSS文件拆分为不同的模块。下图作为参考(图片来源于知乎):
从图中,我们至少分析到几点:
CSS代码根据其职能需要进行分层。(假设应用了预编译语言)
第一层,var或util层(瞎起的😂)。里面保存了sass全局变量、函数、minx等。
第一层,base层。包含CSS Reset和global CSS。
第三层,page层。可以按照上面所拆分的Block进行组织。
通过统一命名前缀可以保证文件按主要功能排列。如
import-lib
、import-module
等等。通过
import
语句进行CSS模块的引用。10 预编译语言
我们运用Less和Sass。
The text was updated successfully, but these errors were encountered: