├── .scss-lint.yml └── README.md /.scss-lint.yml: -------------------------------------------------------------------------------- 1 | severity: error 2 | 3 | linters: 4 | 5 | BorderZero: 6 | enabled: true 7 | convention: zero 8 | 9 | BemDepth: 10 | enabled: true 11 | 12 | DeclarationOrder: 13 | enabled: false 14 | 15 | ExtendDirective: 16 | enabled: true 17 | 18 | LeadingZero: 19 | enabled: false 20 | 21 | NameFormat: 22 | enabled: true 23 | 24 | PrivateNamingConvention: 25 | enabled: true 26 | prefix: _ 27 | 28 | PropertySortOrder: 29 | enabled: false 30 | 31 | QualifyingElement: 32 | enabled: false 33 | 34 | SelectorFormat: 35 | enabled: true 36 | convention: hyphenated_BEM 37 | class_convention: ^(?!js-).* 38 | class_convention_explanation: should not be written in the form js-* 39 | 40 | SingleLinePerProperty: 41 | enabled: true 42 | allow_single_line_rule_sets: false 43 | 44 | StringQuotes: 45 | enabled: true 46 | style: double_quotes 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Airbnb CSS / Sass 指南 2 | 3 | *用更合理的方式写 CSS 和 Sass* 4 | 5 | 翻译自 [Airbnb CSS / Sass Styleguide](https://github.com/airbnb/css) 6 | 7 | ## 目录 8 | 9 | 1. [术语](#terminology) 10 | - [规则声明](#rule-declaration) 11 | - [选择器](#selectors) 12 | - [属性](#properties) 13 | 1. [CSS](#css) 14 | - [格式](#formatting) 15 | - [注释](#comments) 16 | - [OOCSS 和 BEM](#oocss-and-bem) 17 | - [ID 选择器](#id-selectors) 18 | - [JavaScript 钩子](#javascript-hooks) 19 | - [边框](#border) 20 | 1. [Sass](#sass) 21 | - [语法](#syntax) 22 | - [排序](#ordering-of-property-declarations) 23 | - [变量](#variables) 24 | - [Mixins](#mixins) 25 | - [扩展指令](#extend-directive) 26 | - [嵌套选择器](#nested-selectors) 27 | 28 | 29 | ## 术语 30 | 31 | 32 | ### 规则声明 33 | 34 | 我们把一个(或一组)选择器和一组属性称之为 “规则声明”。举个例子: 35 | 36 | ```css 37 | .listing { 38 | font-size: 18px; 39 | line-height: 1.2; 40 | } 41 | ``` 42 | 43 | 44 | ### 选择器 45 | 46 | 在规则声明中,“选择器” 负责选取 DOM 树中的元素,这些元素将被定义的属性所修饰。选择器可以匹配 HTML 元素,也可以匹配一个元素的类名、ID, 或者元素拥有的属性。以下是选择器的例子: 47 | 48 | ```css 49 | .my-element-class { 50 | /* ... */ 51 | } 52 | 53 | [aria-hidden] { 54 | /* ... */ 55 | } 56 | ``` 57 | 58 | 59 | ### 属性 60 | 61 | 最后,属性决定了规则声明里被选择的元素将得到何种样式。属性以键值对形式存在,一个规则声明可以包含一或多个属性定义。以下是属性定义的例子: 62 | 63 | ```css 64 | /* some selector */ { 65 | background: #f1f1f1; 66 | color: #333; 67 | } 68 | ``` 69 | 70 | 71 | ## CSS 72 | 73 | 74 | ### 格式 75 | 76 | * 使用 2 个空格作为缩进。 77 | * 类名建议使用破折号代替驼峰法。如果你使用 BEM,也可以使用下划线(参见下面的 [OOCSS 和 BEM](#oocss-and-bem))。 78 | * 不要使用 ID 选择器。 79 | * 在一个规则声明中应用了多个选择器时,每个选择器独占一行。 80 | * 在规则声明的左大括号 `{` 前加上一个空格。 81 | * 在属性的冒号 `:` 后面加上一个空格,前面不加空格。 82 | * 规则声明的右大括号 `}` 独占一行。 83 | * 规则声明之间用空行分隔开。 84 | 85 | **Bad** 86 | 87 | ```css 88 | .avatar{ 89 | border-radius:50%; 90 | border:2px solid white; } 91 | .no, .nope, .not_good { 92 | // ... 93 | } 94 | #lol-no { 95 | // ... 96 | } 97 | ``` 98 | 99 | **Good** 100 | 101 | ```css 102 | .avatar { 103 | border-radius: 50%; 104 | border: 2px solid white; 105 | } 106 | 107 | .one, 108 | .selector, 109 | .per-line { 110 | // ... 111 | } 112 | ``` 113 | 114 | 115 | ### 注释 116 | 117 | * 建议使用行注释 (在 Sass 中是 `//`) 代替块注释。 118 | * 建议注释独占一行。避免行末注释。 119 | * 给没有自注释的代码写上详细说明,比如: 120 | - 为什么用到了 z-index 121 | - 兼容性处理或者针对特定浏览器的 hack 122 | 123 | 124 | ### OOCSS 和 BEM 125 | 126 | 出于以下原因,我们鼓励使用 OOCSS 和 BEM 的某种组合: 127 | 128 | * 可以帮助我们理清 CSS 和 HTML 之间清晰且严谨的关系。 129 | * 可以帮助我们创建出可重用、易装配的组件。 130 | * 可以减少嵌套,降低特定性。 131 | * 可以帮助我们创建出可扩展的样式表。 132 | 133 | **OOCSS**,也就是 “Object Oriented CSS(面向对象的CSS)”,是一种写 CSS 的方法,其思想就是鼓励你把样式表看作“对象”的集合:创建可重用性、可重复性的代码段让你可以在整个网站中多次使用。 134 | 135 | 参考资料: 136 | 137 | * Nicole Sullivan 的 [OOCSS wiki](https://github.com/stubbornella/oocss/wiki) 138 | * Smashing Magazine 的 [Introduction to OOCSS](http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/) 139 | 140 | **BEM**,也就是 “Block-Element-Modifier”,是一种用于 HTML 和 CSS 类名的_命名约定_。BEM 最初是由 Yandex 提出的,要知道他们拥有巨大的代码库和可伸缩性,BEM 就是为此而生的,并且可以作为一套遵循 OOCSS 的参考指导规范。 141 | 142 | * CSS Trick 的 [BEM 101](https://css-tricks.com/bem-101/) 143 | * Harry Roberts 的 [introduction to BEM](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) 144 | 145 | **示例** 146 | 147 | ```html 148 | 157 | ``` 158 | 159 | ```css 160 | .listing-card { } 161 | .listing-card--featured { } 162 | .listing-card__title { } 163 | .listing-card__content { } 164 | ``` 165 | 166 | * `.listing-card` 是一个块(block),表示高层次的组件。 167 | * `.listing-card__title` 是一个元素(element),它属于 `.listing-card` 的一部分,因此块是由元素组成的。 168 | * `.listing-card--featured` 是一个修饰符(modifier),表示这个块与 `.listing-card` 有着不同的状态或者变化。 169 | 170 | 171 | ### ID 选择器 172 | 173 | 在 CSS 中,虽然可以通过 ID 选择元素,但大家通常都会把这种方式列为反面教材。ID 选择器给你的规则声明带来了不必要的高[优先级](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity),而且 ID 选择器是不可重用的。 174 | 175 | 想要了解关于这个主题的更多内容,参见 [CSS Wizardry 的文章](http://csswizardry.com/2014/07/hacks-for-dealing-with-specificity/),文章中有关于如何处理优先级的内容。 176 | 177 | 178 | ### JavaScript 钩子 179 | 180 | 避免在 CSS 和 JavaScript 中绑定相同的类。否则开发者在重构时通常会出现以下情况:轻则浪费时间在对照查找每个要改变的类,重则因为害怕破坏功能而不敢作出更改。 181 | 182 | 我们推荐在创建用于特定 JavaScript 的类名时,添加 `.js-` 前缀: 183 | 184 | ```html 185 | 186 | ``` 187 | 188 | 189 | ### 边框 190 | 191 | 在定义无边框样式时,使用 `0` 代替 `none`。 192 | 193 | **Bad** 194 | 195 | ```css 196 | .foo { 197 | border: none; 198 | } 199 | ``` 200 | 201 | **Good** 202 | 203 | ```css 204 | .foo { 205 | border: 0; 206 | } 207 | ``` 208 | 209 | 210 | ## Sass 211 | 212 | 213 | ### 语法 214 | 215 | * 使用 `.scss` 的语法,不使用 `.sass` 原本的语法。 216 | * CSS 和 `@include` 声明按照以下逻辑排序(参见下文) 217 | 218 | 219 | ### 属性声明的排序 220 | 221 | 1. 属性声明 222 | 223 | 首先列出除去 `@include` 和嵌套选择器之外的所有属性声明。 224 | 225 | ```scss 226 | .btn-green { 227 | background: green; 228 | font-weight: bold; 229 | // ... 230 | } 231 | ``` 232 | 233 | 2. `@include` 声明 234 | 235 | 紧随后面的是 `@include`,这样可以使得整个选择器的可读性更高。 236 | 237 | ```scss 238 | .btn-green { 239 | background: green; 240 | font-weight: bold; 241 | @include transition(background 0.5s ease); 242 | // ... 243 | } 244 | ``` 245 | 246 | 3. 嵌套选择器 247 | 248 | _如果有必要_用到嵌套选择器,把它们放到最后,在规则声明和嵌套选择器之间要加上空白,相邻嵌套选择器之间也要加上空白。嵌套选择器中的内容也要遵循上述指引。 249 | 250 | ```scss 251 | .btn { 252 | background: green; 253 | font-weight: bold; 254 | @include transition(background 0.5s ease); 255 | 256 | .icon { 257 | margin-right: 10px; 258 | } 259 | } 260 | ``` 261 | 262 | 263 | ### 变量 264 | 265 | 变量名应使用破折号(例如 `$my-variable`)代替 camelCased 和 snake_cased 风格。对于仅用在当前文件的变量,可以在变量名之前添加下划线前缀(例如 `$_my-variable`)。 266 | 267 | 268 | ### Mixins 269 | 270 | 为了让代码遵循 DRY 原则(Don't Repeat Yourself)、增强清晰性或抽象化复杂性,应该使用 mixin,这与那些命名良好的函数的作用是异曲同工的。虽然 mixin 可以不接收参数,但要注意,假如你不压缩负载(比如通过 gzip),这样会导致最终的样式包含不必要的代码重复。 271 | 272 | 273 | ### 扩展指令 274 | 275 | 应避免使用 `@extend` 指令,因为它并不直观,而且具有潜在风险,特别是用在嵌套选择器的时候。即便是在顶层占位符选择器使用扩展,如果选择器的顺序最终会改变,也可能会导致问题。(比如,如果它们存在于其他文件,而加载顺序发生了变化)。其实,使用 @extend 所获得的大部分优化效果,gzip 压缩已经帮助你做到了,因此你只需要通过 mixin 让样式表更符合 DRY 原则就足够了。 276 | 277 | 278 | ### 嵌套选择器 279 | 280 | **请不要让嵌套选择器的深度超过 3 层!** 281 | 282 | ```scss 283 | .page-container { 284 | .content { 285 | .profile { 286 | // STOP! 287 | } 288 | } 289 | } 290 | ``` 291 | 292 | 当遇到以上情况的时候,你也许是这样写 CSS 的: 293 | 294 | * 与 HTML 强耦合的(也是脆弱的)*—或者—* 295 | * 过于具体(强大)*—或者—* 296 | * 没有重用 297 | 298 | 299 | 再说一遍: **永远不要嵌套 ID 选择器!** 300 | 301 | 如果你始终坚持要使用 ID 选择器(劝你三思),那也不应该嵌套它们。如果你正打算这么做,你需要先重新检查你的标签,或者指明原因。如果你想要写出风格良好的 HTML 和 CSS,你是**不**应该这样做的。 302 | --------------------------------------------------------------------------------