[TOC]
# 編寫強健可擴展CSS架構的8條規則
這些是我這些年web開發中從各種大型的復雜的web項目里學到的,已經有很多次別人問我這些知識,所以我覺得是時候把這些心得寫成文檔了。
我會盡量保持解釋的簡潔,會涵蓋以下幾個必要的點:
1. 盡可能使用類
2. 按類存放組件代碼
3. 保持類的命名空間一致性
4. 文件名和命名空間保持一致性
5. 防止樣式泄漏到組件之外
6. 防止組件內的樣式泄漏
7. 尊重組件的邊界
8. 解耦外部的style依賴
# 簡介
如果你從事前端工作的話,你早晚會遇到樣式相關的工作. 雖然各種前端的技術日新月異,但CSS始終堅挺的是前端樣式的唯一選擇(最近,在某些情況下,原生應用程序也是需要的)。 總體來說,樣式的工作方式有兩種大類:
CSS 預處理, 這些年一直使用這種方法 (比如 [SASS](http://sass-lang.com/), [Stylus](http://stylus-lang.com/), 還有一些其他的)
CSS嵌入JS代碼模式, 這是最近才出來的 (例如 [free-style](https://github.com/blakeembrey/free-style), and [其他選擇](https://github.com/MicheleBertoli/css-in-js))
如何在以上的兩種方式中做出選擇是另一個話題了,但就像任何事物的兩面性一樣,這兩種方式都有自己的優缺點,本文中我會更多的討論第一種方式,如果你在使用第二種方式那么本文可能沒那么有意思了.
# 主要目標
我們說的強健的,可擴展的CSS架構, 具體的說到底體現在什么地方呢?
* **面向組件** - 處理UI復雜性的最佳途徑就是將UI拆分成小的組件.如果你已經在使用一個合理的框架,那么Javascript部分已經會是這樣了。例如 React, 就鼓勵高度的組件化和拆分化。我們希望CSS也能夠有這樣的架構體系。
* **沙盒化** - 把UI拆分成各個不同的組件可能會引起各個組件之間樣式的沖突問題。 CSS 的基礎特征例如 層疊樣式,還有獨立和全局的命名空間會讓你出各種亂子. 如果你熟悉 網頁組件細則, 你可以把這當作 影子DOM的樣式獨立 ,而且不用考慮瀏覽器支持 (無論這個細則是否得到支持)。
* **便捷性** - 我們需要這些美好的方法,但不是自己來實現。我們不希望開發者因為使用了我們的架構而感到開發體驗變差了. 我們需要盡一切可能讓這體驗更好。
* **安全性** - 就像之前的觀點提到的,我們希望所有的事情都 默認在本地,只有例外在全局。工程師是一群懶骨頭,總是會尋找最輕松的正確方式來完成任務。
# 詳細的規則
## 1. 優先使用類
這只是在陳述一個顯然的事實。
不要是用目標ID (例如 `#header`),因為每當你認為只有一個實例,但是在長遠看來, 你都會被證明是錯的。我們曾經在一個大型應用上嘗試找出所有數據綁定的問題,我們使用了2個UI,用同樣的DOM, 同樣的數據模型。來確認所有的數據改動都能夠被正確的在UI上顯示,任何你以為唯一的組件(例如標題欄),都不在是唯一了, 這是個簡單的例子能夠證明假設唯一是不靠譜的。好吧,我有點偏題了,我只是想說,永遠不會有情況是指向ID會被指向類更好的,永遠!
同時你也不應該直接指向元素(例如 `p`). 通常情況下你可以直接指向屬于某個組件的元素(詳見下面), 但是對于組件本身而言,如果你這樣做的化,你就早晚會需要去為不需要的組件撤銷樣式。回到我們的主要目標上,這幾乎違反了所有的目標( 非面向組件,未遵循樣式層疊,成為了默認的值)。像字體,行高和顏色( 屬于繼承屬性) 這些body中的屬性可以在你需要的時候成為例外,但是如果你嚴肅的對待組件隔離,這些也完全可以被放棄。(參考下面的 解耦外部的style依賴)
所以除了極少的例外, 您的樣式應始終以類為目標。
## 2. 按類存放組件代碼
當你開發或者使用一個組件的時候,假如所有關于這個組件的內容 - 它的Javascript, 樣式,測試, 文檔 - 都放在一起, 那會很有幫助。
~~~
ui/
├── layout/
| ├── Header.js // 組件代碼
| ├── Header.scss // 組件樣式
| ├── Header.spec.js // 組件單元測試
| └── Header.fixtures.json // 測試代碼的模擬數據 (如需要的話)
├── utils/
| ├── Button.md // 組件使用文檔
| ├── Button.js // ..
| └── Button.scss
~~~
當你使用這些代碼的時候,只要打開項目的目錄,所有相關的組件文件都觸手可得。 這些生成DOM的樣式文件和Javascript有著很自然的聯系, 所以有理由推斷你不會只使用其中的某一個文件。 同理適用于組件及其測試, 比如你可以把這個當作UI組件的[參考地點原則](https://en.wikipedia.org/wiki/Locality_of_reference)。我原來也一直一絲不茍地的維護著不同鏡像下我的代碼,在這些`styles/`, `tests/`, `docs/` 目錄下, 直到我意識到這么做的唯一理由是我習慣那樣。
## 3. 保持類的命名空間一致性
CSS 為類名和其他標識(例如id, 動畫名)準備的命名空間是單獨的也是扁平的。 就像過去使用PHP的日子,開發社區已經適應了這個規則。通過使用更長的,結構化的名字來枚舉名字空間(例如:[BEM](http://getbem.com/))
例如, 我們使用的類名 `myapp-Header-link`,其中的3個部分都有具體的指代:
`myapp` 首先區分于其他在相同DOM下的其他app
`Header` 區分開了同個app下的其他組件組件
`link` 為本地的樣式指定了一個本地的名字(在組件的命名空間下)
作為一個特殊的例子,`Header`組件的根元素作為一個簡單的組件可以直接被 `myapp-Header` 類標記, 這些已經足夠用了。
## 4. 文件名和命名空間保持一致性
這僅僅是兩個規則的合并(按類存放組件代碼和保持類的命名空間一致性), 所有的指定組件的樣式都需要以這個組件命名,沒有例外。
If you're working in the browser, and you spot a component that's misbehaving, you can right-
如果你在瀏覽器里看到一個組件沒有正確的顯示,你可以右鍵點擊它并查看, 例如:
~~~
<div class="myapp-Header">...</div>
~~~
你知道組件名字后,就可以到編輯器里搜索了,“快速打開文件”, 輸入名字"head",你能看到

這樣文件名嚴格的匹配組件名稱非常有用,對于團隊不熟悉架構的新人而言,TA可以輕松而自然的找到應該工作的代碼。
一個很自然(但可能不是很明顯)的推論::一個單獨的樣式文件只能包含單獨名字空間的樣式. 為什么?比如我們有個登陸的表單,只用在 `Header` 組件中。在Javascript代碼中被定義為小組件在`Header.js`中,而且不暴露在外。也許你會定義類名為myapp-LoginForm,同時把這個定義放入 `Header.js` 和 `Header.scss`。 但想象一下,如果一個新的項目成員加入后想登陸表單中的一個布局問題,他打開檢查后會發現沒有`LoginForm.js`和 `LoginForm.scss` ,那他只能通過`grep`來查找相關的代碼。所以,login form需要不同的命名空間,那么就把他放到不同的控件中去。一致性在重大的項目中和金子一樣重要。
## 5. 防止樣式泄漏到組件之外
好了,我們建立了我們的命名空間規則,現在需要對UI控件沙盒化起來了。假如每個控件只使用他們命名空間開頭的樣式類,那么就可以保證樣式不被泄漏到附近的控件中。 這是非常有效的(見下說明), 但不停的輸入名字空間前綴也是一件繁瑣的事情~
一個強健的,同時也機器簡單的解決方案:把整個樣式包裹到一個前綴區塊內。 如下,我們只需要重復應用和組件名字一次:
```css
.myapp-Header {
background: black;
color: white;
&-link {
color: blue;
}
&-signup {
border: 1px solid gray;
}
}
```
以上的例子來自SASS, 但是這個`&`符號,也許讓你驚訝,在所有其他的css預處理語言中都有一樣的功能([SASS](http://sass-lang.com/),[PostCSS](https://github.com/postcss/postcss-nested),[LESS](http://lesscss.org/) 和 [Stylus](http://stylus-lang.com/))。完整的說,下面是SASS編譯后的CSS:
```css
.myapp-Header {
background: black;
color: white;
}
.myapp-Header-link {
color: blue;
}
.myapp-Header-signup {
border: 1px solid gray;
}
```
所有的模式都能和這個契合,例如不同控件狀態下的樣式: (考慮 [Modifier in BEM terms](http://getbem.com/naming/))
```css
.myapp-Header {
&-signup {
display: block;
}
&-isScrolledDown &-signup {
display: none;
}
}
```
會編譯成:
```css
.myapp-Header-signup {
display: block;
}
.myapp-Header-isScrolledDown .myapp-Header-signup {
display: none;
}
```
甚至媒體的查詢都能方便的工作,只要你的預編譯支持冒泡(SASS, LESS, PostCSS 和 Stylus 都有可以):
```css
.myapp-Header {
&-signup {
display: block;
@media (max-width: 500px) {
display: none;
}
}
}
```
編譯為:
```css
.myapp-Header-signup {
display: block;
}
@media (max-width: 500px) {
.myapp-Header-signup {
display: none;
}
}
```
以上的模式使得使用唯一的長類名變得簡單,不用一邊又一邊的重復。便利是必須的,不然的話人們便會偷懶走捷徑。
## 快速的過下JS這邊的情況
這篇文檔是關于樣式約定的,但樣式并不是憑空存在的,JS這邊的一樣需要創造同樣的類命名空間,一樣的需要便利性.
無恥的插播一個廣告,我創建了一個簡單的,0依賴的JS庫來說明,叫做 [css-ns](https://github.com/jareware/css-ns)。當在其他框架中使用的時候,[例如. React](https://github.com/jareware/css-ns#use-with-react),這允許你在指定文件中強制生成一個名字空間:
```jsx
// 創造一個名字空間綁定的React拷貝
var { React } = require('./config/css-ns')('Header');
// 創造元素:
<div className="signup">
<div className="intro">...</div>
<div className="link">...</div>
</div>
```
會這樣繪制DOM:
```html
<div class="myapp-Header-signup">
<div class="myapp-Header-intro">...</div>
<div class="myapp-Header-link">...</div>
</div>
```
這非常方便,以上實現了JS部分的"默認本地"。
我又一次跑題了,讓我們回到CSS吧.
## 6. 防止組件內的樣式泄漏
還記得我之前說的每個類名都需要增加組件前綴是一種很“方便”的沙盒化樣式的方法? 還記得我說過"說明"?
考慮以下的樣式:
```css
.myapp-Header {
a {
color: blue;
}
}
```
和如下的組件層次:
```
+---------------------------------------+
| Header |
| |
| [home] [blog] [kittens] | <-- 這些是 <a> 元素
+---------------------------------------+
```
沒問題吧? 只有在 `Header` 中的 `<a>` 元素 變[藍色](https://www.youtube.com/watch?v=axHe_BVY_9c) , 因為我們定義的規則是:
```css
.myapp-Header a { color: blue; }
```
加入這個布局變化為:
```
+----------------------------------------------------------+
| Header +----------------+ |
| | LoginForm | |
| | | |
| [home] [blog] [kittens] | [info] | | <-- 這些是 <a> 元素
| +----------------+ |
+----------------------------------------------------------+
```
這是選擇`.myapp-Header a` **同時符合了** 在LoginForm中的`<a>`元素,我們所謂的樣式獨立性就被破壞了。 所以說,把所有的樣式都綁定在一個名字空間的區域內是一個有效的方式來實現組件鄰居之間的樣式獨立性,**但對子組件不一定成立。**
以下兩種方式可以修復這個問題:
1. 永遠不要在樣式中指定元素名字, 加入每個在`Header`中的 `<a>` 元素都是 `<a class="myapp-Header-link">` , 那我們就不會有這個問題了。可是,有的時候你已經有很多自定義(語義的)元素名字已經創建好了,而你并不想為他們額外增加類,那么你需要:
2. 通過 [> 連接符](https://developer.mozilla.org/en-US/docs/Web/CSS/Child_selectors) 指定命名空間內的子元素樣式。(譯者:原文的outside感覺并不是作者本意)
對第2種方式, 樣式可以寫作:
```css
.myapp-Header {
> a {
color: blue;
}
}
```
這樣確保了在更深層的組件樹不受當前的樣式影響,因為生成的選擇表達是:.myapp-Header > a. ( 譯者:關于selector可以參考譯者原創的文章 JQuery Selector 入門)
加入你還不確定,讓我提個更加瘋狂的方案,而且這也可行:
```css
.myapp-Header {
> nav > p > a {
color: blue;
}
}
```
這些年來我們一直被教導不要使用嵌套選擇 (當然包括使用 '>') 例如這[許多年的有用例子建議](http://lmgtfy.com/?q=css+nesting+harmful), 為什么?三個理由:
1. 串聯樣式早晚會出事的。你越用嵌套選擇,越有可能從某個不知名的角落出來一個元素剛好符合這個選擇。 你能讀到這里一定了解了我們在之前的建議都在盡力的避免這種可能(嚴格的命名空間前綴,需要時使用子選擇)。
2. 太多的指定破壞了重復使用的可能。樣式目標例如 `nav p a`是沒發在其他地方被使用的,除非有相同的結構。 但我們并不想這樣,事實上我們應該禁止類似這樣的重用,因為他違背了我們的原則:組件樣式需要各自獨立。
3. 太多的指定使得重構艱難。這可是有事實依據的,加入你只是用了 `.myapp-Header-link a`, 你可以隨意的將`<a>` 在你的組件里移動,樣式不會有問題。但對于`> nav > p > a`來說你需要更新選擇來匹配新的位置。但我們說過了,組件需要小而獨立,這樣的工作顯得毫無意義。 當然在重構的時候,你需要考慮應用整體的HTML&CSS,也許挺嚇人的。但加入你只是操作若干只有幾行的沙盒組件, 而且無需關心沙盒外的任何東西,那事情就變的簡單多了。
這是一個理解規則的好例子,讓你知道什么時候可以違反。在這個架構中,不要使用嵌套選擇, 但有些時候確又是正確的事情,祝你好運。
## 好奇的另一面: 防止泄漏樣式進入到組件里
我們已經能夠做到組件的樣式沙盒化,那這些組件是否能確保獨立于整個其他頁面了? 讓我們回憶下:
我們通過使用不同的空間名字空間前綴來避免樣式**泄漏出組件**
~~~
+--------------+
| |
| ------X--->
| |
+-------------+
~~~
擴展的說,這同樣意味著**組件之間**樣式不泄漏。
~~~
+------------+ +------------+
| | | |
| ----------X--------> |
| | | |
+------------+ +------------+
~~~
我們使用了子選擇來防止樣式泄漏**進入子組件**
~~~
+---------------------+
| +-------+ |
| | | |
| ----X------> | |
| | | |
| +-------+ |
+---------------------+
~~~
但嚴重的是,**外部樣式仍然可以泄漏進組件**
~~~
+--------------+
| |
----------> |
| |
+--------------+
~~~
例如,我們有這樣一個組件樣式:
```css
.myapp-Header {
> a {
color: blue;
}
}
```
但當我們引入了一個有問題的第三方庫,它包含了這樣的CSS:
```
a {
font-family: "Comic Sans";
}
```
沒簡單的辦法來保護你的組件不受外部濫用樣式的影響, 這里你只能:

幸運的是,您可以控制您使用的依賴項,并且可以簡單地尋找更加良好的替代方案。
不過,我只是說沒有簡單的方法來保護你的控件,但這并不意味這沒有任何方法了。[哥們,有辦法的](https://www.youtube.com/watch?v=20wUS_bbOHY),只是任何辦法都有代價的。
* 使用強行重置: 加入你對每個組件的每個元素都引入[css重置](http://cssreset.com/what-is-a-css-reset/), 然后放到一個總是能比第3方更優先的選擇中,那么就可以了。 但除非你的應用非常的小,(例如3方應用的一個“分享”按鈕),這樣的方式很快就會超出你的控制。所以這并不是一個好的主意,列在這里只是為了完整性.
* [`all: initial`](https://developer.mozilla.org/en/docs/Web/CSS/all) 是個不被人知的新CSS屬性,它就是設計來解決這個問題的,它能夠[阻擋繼承的屬性](https://jsfiddle.net/0d9htatc/)進入,而且能夠將本地的屬性重置 [如果它能贏得協議的話](https://jsfiddle.net/e7rw4L8L/). 這個實現包含了一些[復雜因素](https://speakerdeck.com/csswizardry/refactoring-css-without-losing-your-mind?slide=39),可能[不是每個地方都支持](http://caniuse.com/#feat=css-all), 但相信我,`all: initial`可能成為樣式獨立非常有用的工具.
* Shadow DOM(影子DOM)已經提到了,這也是解決這個問題的很好方式,它允許定義JS和CSS清晰的邊界. 除了[近期的一些希望](https://developer.apple.com/library/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html), 這網頁組件的協議近幾年來并沒有更新, 除非你的目標瀏覽器是明確的,你沒法正式的使用Shadow DOM.
* 最后的方法就是 `<iframe>`了,這提供了最強大的網頁運行時獨立環境(對JS和CSS都一樣), 但同時也會帶來啟動和運行效率的懲罰。 但這樣的代價有時候是值得的,那些最接觸的網頁嵌入(例如Facebook, Twitter, Disqus)事實上就是用iframes寫的。但為了這篇文檔的出發點 - 獨立成千上萬個小的組件會讓你的開銷成百倍的增加。
這次走題有點長了,回到CSS。
## 7. 尊重組件的邊界
就像我們樣式 .myapp-Header > a, 當我們嵌套一個組件時候,我們可能要對子組件設置一些樣式, 考慮這布局:
~~~
+---------------------------------+
| Header +------------+ |
| | LoginForm | |
| | | |
| | +--------+ | |
| +--------+ | | Button | | |
| | Button | | +--------+ | |
| +--------+ +------------+ |
+---------------------------------+
~~~
我們立即可以看到樣式 `.myapp-Header .myapp-Button` 不是個好主意,顯然我們應該這樣寫 `.myapp-Header > .myapp-Button`。 但什么樣式是我們可能會希望子組件也繼承的呢?
注意到 `LoginForm` 被鎖定在 `Header` 欄的右邊,直覺上,下面的樣式需要:
```css
.myapp-LoginForm {
float: right;
}
```
我們還沒違反任何規定,但我們也讓 `LoginForm` 變的難以重用了, 如果我們下面的主要需要`LoginForm`, 但又不是右浮動的,那就沒戲了。
實用的解決方法是部分的放松我們之前的規則,只寫當前名字控件的組件樣式。 我們可以這樣做:
```css
.myapp-Header {
> .myapp-LoginForm {
float: right;
}
}
```
這其實很完美,只要我們不破壞子組件的沙盒性。
```css
// COUNTER-EXAMPLE; DON'T DO THIS
.myapp-Header {
> .myapp-LoginForm {
color: blue;
padding: 20px;
}
}
```
看起來我們并不希望這樣,因為我們失去了對本地樣式的保護,全局樣式可以影響了。 同時上面的代碼中,LoginForm.scss 不再是唯一一個地方你能看到LoginForm組件的樣式了,這聽起來挺可怕的,那么,我們到底如何區分什么是可以的什么是不可以的呢?
我們希望尊重每個子組件中的沙箱,因為我們不希望依賴于它的實現細節。對我們來說這是一個黑盒子。相反,在子組件之外的是父組件的沙箱,它在其中占主導地位。內部和外部的區別來自于CSS中最基本的概念之一:[the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model)。

我的推理并不好,但詳細的說是這樣的: 就像在國家內意味這在他的邊界內,我們認為父節點只能影響它直接下一代的子節點組件邊界外的屬性. 這意味著和位置與像素相關的屬性(例如position, margin, display, width, float, z-index 等), 但那些涉及到邊界之內的屬性(例如border本身,padding, color, font等)就不行。
綜上,以下這種寫法是不允許的:
```css
// 反例; 請不要這樣寫
.myapp-Header {
> .myapp-LoginForm {
> a { // 依賴 LoginForm 的詳細實現
color: blue;
}
}
}
```
但也有一些有趣的邊界情況,比如:
* `box-shadow` - 一種特定類型的陰影可以整合成為組件外觀的一部分,所以它應該成為自有的樣式。但同時,視覺上的感受它明顯是在邊界以外的, 從這個角度它又該屬于父節點組件的一部分。
* `color`, `font` 和其它 [繼承的屬性](https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance) - `.myapp-Header > .myapp-LoginForm { color: red }` 涉及到了內部的子組件, 但同時來說也相當于函數 `.myapp-Header { color: red; }`, 這也是符合我們的規則的.
* `display` -加入子組件用了 [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)布局, 很有可能在根元素上設置了 `display: flex` 屬性. 但是,父節點可以選擇設置 `display: none` 來隱藏子節點。
對于這些邊界條件下的情況,你需要清楚的認識到這沒什么大不了的,只是一點點CSS串聯進你樣式。 比起其他讓你煩惱的事情來說,你完全可以接受適度的串聯。 例如這個例子[指定內容](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity), 就像你期望的那樣展現:當組件可見時,`.myapp-LoginForm { display: flex }`是指定的,當需要隱藏時,`.myapp-Header-loginBoxHidden > .myapp-LoginBox { display: none }`成為了指定的樣式。
## 8. 解耦外部的style依賴
為了避免重復造輪子,有時候你需要在組件間共享樣式, 有時候你也需要使用其他人創建的樣式。 這樣的情況下,就需要避免對代碼長生比不要的依賴影響.
一個很實在的例子, 我們來用一些來自 [Bootstrap](http://getbootstrap.com/css/) 的樣式, 作為那些整合起來讓人頭大的框架的一個完美例子. 考慮我們上面所提到的所有內容,說到把所有的樣式放到一個全局的名字空間是個很壞的習慣,然而Bootstrap:
* 往全局名字空間里導出了非常多的選擇器 (準確的說2481個,對于版本3.3.7), 不管你是不是要用。(一花費了很多天來調試這個問題..)
* 使用硬編碼的類名字類如 `.btn` 和 `.table`。 沒法想象如果這些如果被其他開發者或者項目重用的話是多么恐怖的事情.
先不管上面這些,假定我們要使用Bootstrap作為我們Button組件的基礎。
而不是在HTML方面集成:
```html
<button class="myapp-Button btn">
```
考慮在您的樣式中[擴展](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#extend)類:
```html
<button class="myapp-Button">
```
```css
.myapp-Button {
@extend .btn; // from Bootstrap
}
```
這樣做的話,可沒人能夠知道你這個組件的樣式是荒謬的依賴于`btn`類的 `Button` 原始的樣式實現是完全沒必要在外部展示的。作為一個結果,一旦你放棄bootstrap轉用別的框架(或者自己寫樣式),這樣的改變從代碼層面是很難體現出來的,但結果就是.. 哈哈 你的`Button`樣子變了!
同樣的原則你應該用自己的幫助類, 這里你也許會選擇更合理的名字,例如:
```css
.myapp-Button {
@extend .myapp-utils-button; // 在項目其他地方定義
}
```
或者 [只是占位類](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#placeholder_selectors_) altogether ([主流預編譯都支持](https://csspre.com/placeholder-selectors/)):
```
.myapp-Button {
@extend %myapp-utils-button; // 在項目其他地方定義
}
```
最后,所有主流的css預編譯工具都支持 [mixins](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#mixins), 這同樣十分的有用.
```css
.myapp-Button {
@include myapp-generateCoolButton($padding: 15px, $withExplosions: true);
}
```
必須指出現在很多良好的框架(例如 [Bourbon](http://bourbon.io/) 或者 [Foundation](http://foundation.zurb.com/)),它們就是像上面這樣做的:聲明一些列的mixins給你按需來使用,才不會散發他們自己的樣式. [Neat](http://neat.bourbon.io/)。
# 結束語
> 熟悉規則了,才能更好的知道什么時候打破規則。
最后,就像上面提到的,你熟悉了解了你所依賴的這些規則(無論是陌生人告訴你的還是你從網上學的),你才能合理的做一些例外的事情。 例如,如果你需要直接增加一個幫助類,你可以這么做:
```html
<button class="myapp-Button myapp-utils-button">
```
這個添加的值可以,舉例來說,幫助你的測試框架來自動識別這是一個可以被點擊的按鈕。
或者你也可以決定偶爾打破下組件隔離的規矩,小小的違背下, 因為如果要完全實現組件分割的代價會很大。 雖然我也許會提醒你這可能會有風險,最好還是保持一致,但只要你的團隊ok,你又完成任務了,那也沒問題的!
# License
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
# 參考
> 原文地址 [8 simple rules for a robust, scalable CSS architecture](https://github.com/jareware/css-architecture) 本文僅僅是對原文的中文翻譯, 所有權利歸原作者 Jarno Rantanen.
簡書:https://www.jianshu.com/p/acb4b9d8ff4f
- 必備基礎
- 基礎知識
- BFC
- 層疊上下文 Stacking Context
- 視覺格式化模型 Visual formatting model
- CSS3中使用HSL顏色指南
- z-index
- line-height
- vertical-align 屬性
- 垂直居中
- overflow
- CSS3 Gradients
- CSS3 動畫基礎
- 難點知識
- 布局篇
- Flex布局
- =====
- Grid布局
- 多列布局
- 高級布局
- 預編譯器篇
- PostCSS
- Sass
- stylus
- 模塊篇
- 良好的使用
- CSS 模塊化
- 技巧篇
- 未來的CSS
- 動畫篇
- 工具篇
- CSS架構
- CSS 命名方法論
- BEM
- CSS解釋器
- 常用框架
- 參考
- 唰唰聲