構建穩固的、可升縮的CSS框架的八大原則
構建穩固的、可升縮的CSS框架的八大原則
這些原則都是我從這些年工作中所含蓋的各個大型、復雜的web項目中總結出來的。而這些事情也都是我這些年被多次問到的,所以覺得將其用文檔的形式敘述出來會是個不錯的想法。
我會嘗試著盡量縮短我的解釋,以下是關鍵詞:
-
將組件的相關代碼放在一起
-
讓命名空間和文件名間具有映射關系
-
### 防止泄漏組件內的樣式
簡介
如果你從事前端的應用開發,那么你一定會需要設置樣式。盡管現在優秀的前端應用花樣百出,但CSS仍然是賦予網頁上任何東西樣式的唯一方法(但是,在某些情況下, 原生的應用 也可以做到)。也就是說,這篇文章將講到兩大類設置樣式的方法,即:
-
相對而言,才出現的具有CSS-in-JS 特性的庫 (如 free-style , 和 many others )
對于這兩種方案的選擇完全可以另立文章進行講解。當然, 它們也都有各自的優缺點。盡管如此,我將集中介紹前一種方法, 所以,如果你選擇“追隨”后者,那么這篇文章對于你而言會比較乏味。
高層次目標
我們追求的是一個穩固的、可升縮的CSS框架。但是要做到這一點,究竟需要具備些什么特質呢?
-
面向組件- 處理UI復雜性的最佳方法就是講UI分成許多很小的組件。如果你使用了一個“明智的”框架,你就會發現在JS方面也是如此。 比如, React 就具有高度組件化的特性。由此,我們希望CSS框架也能如此。
-
沙盒- 將組建進行拆分并不一定能能使得其按照我們的期望進行加載,如:一個組件的樣式可能會對其他組件的樣式產生不可預計的影響。諸如 cascade 這樣的CSS基礎特性和具有唯一全局性性質的命名空間的標識符就能造成這種影響。如果你對 Web組件的規范 比較熟悉, 你就可以開始考慮利用 Shadow DOM可以隔離樣式的優勢 來做些什么而不必去關心瀏覽器的支持程度(或是否有相應的規范)。
-
易用性- 我們想要一切“漂亮”的事物,但是又不想做過多工作。也就是說,我們并不想要開發者在運用該框架時具有較差的體驗。如果可以,我們想將其做的更好。
-
容錯性- 與前面的觀點有點聯系的是,我們希望一切的東西默認都具有本地性,當然,異常除外。而我們工程師都很懶,而通常阻力最小的方案總被證明是正確的解決方案。
1. 善用類來定義CSS
This is just to get the obvious out of the way.
不使用ID (e.g. #header ), 因為當你認為這將只是一個事物的實例的時候,你都會被現實-- 在無限的時間尺度上 ]--很扇一個耳光。這是我們過去發生過的一個案例。當時我們嘗試著去剔除一個大型應用中的數據綁定bug,因此我們在同一DOM樹中并列使用了兩個運用了這個UI庫的實例, 而這兩個都綁定到了一個名為shared的實例上。 最初,這是為了保證數據模型中的所有修改都能正確的反映到UI庫上。然而此時,任意你覺得會是獨一無二的組件,如:header bar,都將不復存在。這也是一個發現與獨特性假設相關的不易察覺的bug的標準方法。 這個事情的道理在于: 沒有相關的解決方法會使得運用ID的方法比運用class的方法好。 所以讓我們永遠不要使用ID吧。
同樣的,你也不能直接指定你的目標元素。 但是如果目標元素在某個組件里,直接指定到是可行。但最終,你需要去 清除這些對于組件而言無用的樣式 。 而對于我們更高級別的目標來說,這與其是完全相背離的。而設置body上的屬性,如:fonts、 line-heights 和colors (又名 可繼承的屬性 ) 卻是一個特例。 但是如果你格外在意組件的獨立性的話, 放棄這些是完全可行的(如中所說的一樣).
所以,除了某些特定的場合,你的樣式設置最好使用class。
2.將組件的相關代碼放在一起
當在設置一個組建的時候,如果能將其相關部分--js文件、css文件、測試文件等--聚集起來,會對組件的組件化起到很大的作用。
ui/
├── layout/
| ├── Header.js // component code
| ├── Header.scss // component styles
| ├── Header.spec.js // component-specific unit tests
| └── Header.fixtures.json // any mock data the component tests might need
├── utils/
| ├── Button.md // usage documentation for the component
| ├── Button.js // ...and so on, you get the idea
| └── Button.scss
當你在進行編碼的時候,只需要打開你的項目編輯器即可。而生成DOM樹的js文件和css文件通常具有相關性,我敢打賭你會在編輯過其中一個文件后很快地轉向另一個文件的編寫。比如:同一個組件中的css和js文件,又或者其相關的測試文件夾中的css和js文件。我們可以將這個看作是UI組建的 局部引用原則 。當然,我也把這個規則運用于維護我源碼樹中各個獨立部分的工作中,如: styles/ , tests/ , docs/ 等部分。
對于類名和其他標識符(如ID、動畫名稱等)而言,CSS只具有一個單一的、無區分性的命名空間。而對于這一問題的解決方法,人們采用了與過去的PHP時代一樣的解決方法,即:使用長而具有結構性的命名方式( BEM 來完成對于命名空間的命名。我們將選用一種命名標準并貫徹執行。
舉個例來說, 用 myapp-Header-link 作為一個類名. 而它的每一個部分都有明確的功能:
-
myapp :用于區分使用在同一DOM樹上的不同app
-
Header :用于區分app中的不同組件
-
link : 聲明了組件空間中的一個局部名稱,達到了我們想設置局部樣式的目的
但有一個特例,就是 Header 組建的根元素只需要使用 myapp-Header 這個類名進行標識即可。并且對于一個簡單的組件而言,這可能就是你所全部需要的命名。
不管是采用了哪一個命名規范,我們都需要堅持使用這一種方法。而這種命名方式中的三個部分除了有其特定的功能,還具有相應的含義。故而在看到一個類名的時候,你會看出它屬于哪個部分。也就是說,命名空間可以幫助我們在瀏覽項目的樣式文件時準確歸類。
我將這種命名的模式設定為: app-Component-class , 而且這也是我工作中行之有效的方法。當然,你也可以提出你自己的設置模式。
4. 讓命名空間和文件名間具有映射關系
這一條規則是上面兩條規則(將相關代碼放在一起,類的命名空間)的組合,即:所有會影響到同一組件的樣式規則應該放在以該組件命名的文件中。
如果你正在使用瀏覽器觀看效果,并且定位到一個表現異常的組件,你可以依次點開這個組件,假設你會看到以下代碼:
<div class="myapp-Header">...</div>
接著你可以切換到你的編輯器,在敲擊了“快速打開文件”的組合鍵之后,利用你剛獲取到的名稱--head--進行搜索,然后看到:
而UI組件和其對應的編碼文件間所具有的嚴格映射,對于新進入項目而又不熟悉項目架構的人來說無疑是有用的。
當然,還有一個推論(雖然現在可能不太明顯):一個樣式文件中應該只含有一個命名空間中的樣式。為什么這么說呢? 舉個例子吧。現在有一個登陸的表單,它只會用在 Header 組件中. 而與其相關的js,我們定義在了一個名為 Header.js 的文件中, 并且不會向其他地方“暴露”該文件。然后,給這個表單賦予了一個類名,即 myapp-LoginForm , 并將在 Header.js 文件和 Header.scss 使用它。現在,假設有一個新來的人要去修改這個登錄表單在布局上的一些小問題 并且他要去判斷從哪個元素開始入手。此時,又沒有 LoginForm.js 文件或者 LoginForm.scss 文件 。故而,他不得不求助于 grep 這些工具或者靠猜測去找到相關代碼文件。也就是說,如果這個登錄表單需要一個獨立的命名空間,我們就需要將其放在一個獨立的組件中。而這種一致性在工程項目中具有重要的價值,因為它避免了猜測查找.
5. 防止在組件外定義樣式
我們已經展示了我們常用的命名規則,現在我們想將這些規則應用到UI組件上。如果所有的組件都只使用了附有獨特命名空間前綴的類名, 我們敢說這些樣式絕對不會和它人的重合。 從下面會涉及到的注意事項中不難看出這一方法的意義性。但是一遍遍重復的編寫這些命名空間確實會讓人覺得厭煩。
一個行之有效且非常便捷的方法便是將文件中所涉及到的全部樣式放在一個標有前綴名的塊中。注意我們是怎么只輸入一次app或者組件所需要重復使用的名字的:
.myapp-Header {
background: black;
color: white;
&-link {
color: blue;
}
&-signup {
border: 1px solid gray;
}
}</code></pre>
雖然上面的例子都是運用在SASS中的,但是喜人的是 & 這個符號可以在所有相關的css預編輯器中使用 — ( SASS , PostCSS , LESS 和 Stylus )。下面所展示的便是上面的代碼在SASS中的編譯結果:
.myapp-Header {
background: black;
color: white;
}
.myapp-Header-link {
color: blue;
}
.myapp-Header-signup {
border: 1px solid gray;
}</code></pre>
所有經常使用的模式在該種定義下都能很好地被編譯出來,例如: 為不同狀態下的組件設置不同的樣式( Modifier in BEM terms ):
.myapp-Header {
&-signup {
display: block;
}
&-isScrolledDown &-signup {
display: none;
}
}</code></pre>
編譯結果:
.myapp-Header-signup {
display: block;
}
.myapp-Header-isScrolledDown .myapp-Header-signup {
display: none;
}</code></pre>
即使是對于媒體查詢的設置也能很方便的進行,只要你使用的預編輯器支持“冒泡”這個功能。(SASS, LESS, PostCSS and Stylus都支持):
.myapp-Header {
&-signup {
display: block;
@media (max-width: 500px) {
display: none;
}
}
}</code></pre>
編譯結果:
.myapp-Header-signup {
display: block;
}
@media (max-width: 500px) {
.myapp-Header-signup {
display: none;
}
}</code></pre>
上面所提到的方法使得我們不用一遍遍地編寫重用的代碼就能使用長但卻獨一無二的類名。而這種便捷性是必須要考慮到的。因為一旦沒有了便捷性,我們便會“偷工減料”。
在JS文件里快速命名
雖然這部分是關于樣式設置的便捷性的,但是樣式并不會獨立存在。也就是說,JS文件里同樣需要以相同的命名方式快速地完成命名工作。
“無恥”的做個宣傳,我已經編寫出了一個完全不依賴任何JS庫的簡單方法來實現這一功能,即: css-ns 。當其與框架層一同使用時 ( 如:React ),會在一個指定的文件中 強行 加上特定的命名空間,如:
// Create a namespace-bound local copy of React:
var { React } = require('./config/css-ns')('Header');
// Create some elements:
<div className="signup">
<div className="intro">...</div>
<div className="link">...</div>
</div></code></pre>
渲染而成的DOM樹為:
<div class="myapp-Header-signup">
<div class="myapp-Header-intro">...</div>
<div class="myapp-Header-link">...</div>
</div>
這很便捷,而且該JS文件可以直接在本地使用。哎,我又再一次離題了。重新回到CSS上吧!
6. 防止泄漏組件內的樣式
還記得我說過每個類名前面加上組件的名稱空間是一個“非常有效”的沙盒風格嗎?還記得我說過這種方法有“注意事項”嗎?
看一下下面的樣式:
.myapp-Header {
a {
color: blue;
}
}
下面是組件的等級分布圖:
+-------------------------+
| Header |
| |
| [home] [blog] [kittens] | <-- these are <a> elements
+-------------------------+
我們很酷,對嗎??只有 Header 里的元素有 blued 樣式,這是由我們生成的規則決定的:
.myapp-Header a { color: blue; }
但是如果布局變成了下面的結構:
+-----------------------------------------+
| Header +-----------+ |
| | LoginForm | |
| | | |
| [home] [blog] [kittens] | [info] | | <-- these are <a> elements
| +-----------+ |
+-----------------------------------------+
.myapp-Header a 這個選擇規則 同樣適配 于 LoginForm 里的元素, and we've blown our style isolation. 這也說明了一個事實:將所有的樣式放在一個命名空間下確實是一個將其與其他組件相區分的有效方法, 但是卻不能有效地區分其內部元素的樣式 .
可以用以下兩種方法改善這個問題:
- 決不在樣式文件中使用元素名稱。如果 Header 組件里的所有元素都不相同,那么我們也不用去處理這個問題。但是 為了更好地建立語義標注,有時會在不同的地方使用多個相同的元素 ,而且你也不想用多余的類名去區分他們,那么在這種情況下,我們采用第二種方法。
-
在命名空間中將元素名與選擇器“ > ”配合使用。 應用該種方法后, 我們的樣式重寫為:
.myapp-Header {
> a {
color: blue;
}
}
當然,因為此時的選擇器為 .myapp-Header > a ,這會使得“樣式隔離”對于組件樹中深層次的元素同樣奏效。如果這不能讓你信服,我們可以看一下下邊這個同樣湊效的例子:
.myapp-Header {
> nav > p > a {
color: blue;
}
}
在文章 多年的可行經驗 中,我們被告知要避免使用選擇器的嵌套(包括 > ) 。為什么呢?作者陳列出了以下三個原因:
-
級聯風格最終將毀了你一天。選擇器嵌套的越多,越可能在無意間與多個樣式選擇規則相匹配。讀到這,你該知道我們已經排除了這種可能性--使用了嚴格的命名空間前綴且在需要的地方使用了孩子選擇器。
-
太多的特異性將減少可重用性。如: nav p a 這樣的樣式規則即使是在特定的環境下也不能被復用。但是我們也不希望發生這種情況。事實上,當樣式規則不能與我們的目標--組件間的相互隔離--相契合時,我們會禁止這種樣式的復用性。
-
過多的特異性會使重構困難。該種情況在現實中有所體現。比如:在 .myapp-Header-link a 這條規則下,你可以隨意在你的HTML組件里移動a元素,且同樣的樣式仍舊起作用。然而一旦使用的是 > nav > p > a 這樣的規則,你就需要更新選擇器以匹配a元素在該HTML組件中的新位置。但考慮到我們想通過小且具有隔離性的組件來組裝UI庫時,這個理由也就沒有了實際意義。當然,如果你不得不在重構項目時考慮到全部的HTML和CSS文件,這將帶來可怕后果。但是如果你是將一個個具有樣式的小沙盒組合起來使用并且知道沙箱之外的都不需要納入考量,那么這種類型的變化就不再是一個問題。
這是一個很好的例子來幫助你理解這個規則。于是,你會知道該在什么時候打破這個規則。在我們的架構中,選擇器嵌套不只是可行的,有時它是你不得不去做的事情。為它而瘋狂吧!
防止將樣式注入到組件中
當我們為我們的樣式規則設置了“沙盒”之后,這些組件是否都能獨立于彼此而獨立存在了呢 ?簡要介紹一下:
- 通過在每個類名前加上組件的命名空間防止了樣式向 組件外部 泄露的問題:
+-------+
| |
| -----X--->
| |
+-------+
- 除此之外,該種方法還防止了 項目組件間 的影響問題:
+-------+ +-------+
| | | |
| ------X------> |
| | | |
+-------+ +-------+
- 通過使用孩子選擇器我們還防止了 組件內的組件 被影響:
+---------------------+
| +-------+ |
| | | |
| ----X------> | |
| | | |
| +-------+ |
+---------------------+
- 但是,值得注意的是, 外部樣式可以“入侵”到我們的組件中來 :
+-------+
| |
----------> |
| |
+-------+
比如,我們的組件具有以下的樣式規則:
.myapp-Header {
> a {
color: blue;
}
}
但是我們引入了有“不良行為”的第三方庫,它包含了以下的CSS樣式:
a {
font-family: "Comic Sans";
}
目前沒有簡單的方法能規避這樣的問題--external abuse , 所以我們通常舉手投降。

幸運的是,你通常可以在一定程度上控制你引入的庫, 而且可以很快的找到一個表現良好的替代方案。
當然,我是說過沒有簡單的方法來幫助你規避這個問題,但是并不代表沒有。 這些方法 里提出了很多折中的解決方案:
-
直接覆蓋: 如果你引入了 CSS reset ,并將其設置到相應的能“勝過”第三方組件設定的規則的選擇器上,你就成功了。但是只要你的應用很小(也就是說,一個第三方共享的button組件都能嵌入到你的網頁), 這個方法就會失效。所以,這并不是個好方法,列在這兒只是為了方法論介紹的完整性。
-
all: initial 是一個鮮為人知的CSS屬性。它的作用便是用于處理這種問題。除了可以 阻止一個元素繼承屬性 , 還能作為局部樣式的重置方法使用, 只要其具有特異性爭議 (and as long as you repeat it for each element you want to protect). Its implementation includes some intricacies 并且 并未得到全部瀏覽器的支持 ,但是最終 all: initial 可能成為一個隔離style設置的有效工具。
-
Shadow DOM在上面已經提到過了。 它可以作為處理該項任務的一個工具,因其能在js和css中對組建的邊界進行明確的聲明。 盡管 在最近的safari版本中看到了一些希望 ,但是近年來,對于 Web組件規范的支持并沒有多大進展。所以 除非你只考慮在已經支持的瀏覽器上工作,否則不要依賴于Shadow DOM去解決問題.
-
最后, 便是...[原文里沒有,KX上網沒成功,所以我也不知道是什么]。它提供了一種方法來隔離CSS和JS文件的運行時間,但與此同時,也會增加啟動成本--來源于延遲和維護成本--來源于內存的保持。然而通常情況下,這種折中是值得的。 對于大多常用網站的嵌入(如:非死book, 推ter, Disqus等)都是使用 iframes實現的. 然而對于本文想實現的目標--將成千上萬的小組件相互分離--而言,這種方法會大幅度降低我們的預期。
不管怎么樣,這節的篇幅有點長了,讓我們回到我們所列的CSS規則上吧。
7. 考慮組件的邊界問題
正如 .myapp-Header > a 這條規則一樣,當我們想嵌入子元素的時候 ,我們可能需要對子元素應用相應的樣式規則 。而不像web組件一樣,在處理 > a 和 > my-custom-a 時沒有任何區別。考慮下面這個布局:
+---------------------------------+
| Header +------------+ |
| | LoginForm | |
| | | |
| | +--------+ | |
| +--------+ | | Button | | |
| | Button | | +--------+ | |
| +--------+ +------------+ |
+---------------------------------+
我們能馬上注意到設置 .myapp-Header .myapp-Button 這樣一條規則會非常糟糕,所以我們會使用 .myapp-Header > .myapp-Button 這條規則。但是什么樣的規則才是我們想應用到子元素中的呢? 當想讓 LoginForm 元素位于 Header 元素的右側時,有人會這樣定義:
.myapp-LoginForm {
float: right;
}
這個定義沒有違反我們制定的任何規則,但是這會使得 LoginForm 的樣式規則不太好被重用。例如:當頁面想重復使用 LoginForm 元素時, 此時重用的的 LoginForm 就并不具備向右浮動的布局。哎,真糟糕!此時,通常的解決方法就是放寬先前指定的規則,而使得該規則可以應用到該文件所屬的命名空間中。也就是說,我們應該如此制定規則:
.myapp-Header {
> .myapp-LoginForm {
float: right;
}
}
只要你不隨意地設置會影響到子元素盒模型的樣式,這個規則還是能很好地起作用的。
// 不好的例子; 不要這樣做
.myapp-Header {
> .myapp-LoginForm {
color: blue;
padding: 20px;
}
}
我們不允許這樣做的原因是在于這樣的設置會打破局部修改不應該對全局造成影響的原則。并且使用了上述編碼之后, LoginForm.scss 文件就不再是你在需要改變 LoginForm 組件元素樣式時所需要考察的唯一文件了。這時的改變將牽連甚廣。那么可不可以的評判標準是什么呢?
為了不依賴于樣式的實現細節,我們希望每一個子組件都能有其自己的“界限”。也就是說,對于我們而言,它們是黑盒。相反地,這些子組件之外的便隸屬于父組件自身。內、外的區分來自于CSS中的一個最基礎的概念: 盒模型 .

我的類比很糟糕,但接下來的不是:就像“在一個國家”意味著在其物理邊界中一樣,我們聲明在border外部有一個父元素可以對其內的(直接)子元素的樣式造成影響。也就是說,那些會影響定位和尺寸大小的屬性,如: position , margin , display , width , float , z-index 等在外部(父元素)中聲明是被允許的,但是那些會對邊界里的內容造成影響的屬性,如: border , padding , color , font 等的設置就是不被允許的。 是以,按照該推論,下面這樣的方式也是不被允許的 :
// 反例; 不要這樣做
.myapp-Header {
> .myapp-LoginForm {
> a { // relying on implementation details of LoginForm ;__;
color: blue;
}
}
}
下面有一些特例:
-
box-shadow - 作為一個陰影類型,從感觀上來說可以作為一個元素的一部分, 也因此其應該包含所有的樣式。重申一下,該屬性設置的視覺效果能清楚地呈現在邊框之外,所以它會進入其父組件的區域內。
-
color , font 和其他 可被繼承的屬性 - .myapp-Header > .myapp-LoginForm { color: red } 這樣的設置規則會影響到其內子組件的樣式。從另一方面來說,它等同于 .myapp-Header { color: red; } 這樣的設置, 而這在我們的規則中是被允許的。
-
display - 如果子組件使用了 彈性布局 ,它可能依賴于其根元素上設置了 display: flex 的樣式。但是,它的父元素可能會使用 display: none 來隱藏掉這些子元素。
我們需要注意到的是,在這些特例中使用一些級聯樣式來設置你期望的樣式是可行的。是要注意適度使用級聯設置即可。 舉例來說,讓我們來好好分析一下最新的一個例子。在該例子上, 這些判定規則 保證了這些規則如你期望般的工作,即:當元素是可見的時候, .myapp-LoginForm { display: flex } 就是其適用的最具體的一條規則。當其父元素決定隱藏這些元素時,會使用 .myapp-Header-loginBoxHidden > .myapp-LoginBox { display: none } 這樣的規則。而這樣的規則更具體,所以成功隱藏了這些元素。
8. 松散的聚合外來樣式
為了避免重復的工作,有時也需要使得不同的元素間共享樣式規則。而為了逃避這一工作,你可能會想使用由其他人創建的樣式。但無論是哪一種方法,都應該保證不會在代碼庫中創建不必要且耦合的代碼。 作為一個具體的例子,讓我們考慮使用 Bootstrap --作為一個規避了這些問題的框架--中的一些樣式。Bootstrap考慮到了上面所討論過的問題,也使用了單一的全局命名空間來管理樣式,但有以下不好的點:
-
不管你是否使用,它向外暴露了很多選擇器 (對于 3.3.7的版本, 已有2481個) 。 (有趣的旁白:直至IE9,它能處理的選擇器也只有4095個。我曾聽說有人花了數天進行調試就是想要知道到底發生了什么。)
-
使用硬編碼的類命名方式,如: .btn 和 .table 。難以想象的是這些類名被其他開發者或者項目所使用。
盡管如此,我們只能將Bootstrap作為 Button 組件的基礎使用。
我們要做的并不是像下面這樣融合代碼:
<button class="myapp-Button btn">
而是考慮 繼承 樣式:
<button class="myapp-Button">
.myapp-Button {
@extend .btn; // from Bootstrap
}
這么做的好處在于不會讓包括自己在內的所有人產生一個想法,即:你的樣式依賴于類名為 btn 的樣式 。 Button 的樣式應該只來源于自身而不會受外部的影響。因此,無論你是使用Bootstrap還是其它框架,亦或者你自己編寫代碼,都應該遵循一個原則:針對于該類元素的設置不能影響到其它元素。
同樣的原則也適用于自己編寫的類,此時,你就可以選擇使用更合理的類名:
.myapp-Button {
@extend .myapp-utils-button; // defined elsewhere in your project
}
或者 在適當的時候引入所需類 ( 被大多數預處理器所支持 ):
.myapp-Button {
@extend %myapp-utils-button; // defined elsewhere in your project
}
最后,所有的CSS預編輯器都支持 mixins 這一概念。
.myapp-Button {
@include myapp-generateCoolButton($padding: 15px, $withExplosions: true);
}
應該注意的是,當使用更友好的框架(如: Bourbon 或者 Foundation )時,他們實際上會做的事只是:定義好了一堆mixin指令供你在需要的地方使用,而不會隨意暴露出風格樣式。 Neat 。
結束語
知道這些規則后,才能知道在什么時候可以去打破它
最后,正如前面所提到的一樣,當你理解了這些列出的規則之后 ,你就可以判斷它對于你來說的價值。例如, 你覺得使用輔助類是有價值的,你就可以這樣編碼:
<button class="myapp-Button myapp-utils-button">
這就好比你在測試框架的時候所獲得的附加價值值。它讓你能更快速地找出可以作為按鈕并能被點擊的事物。 或者你能做出這樣的決斷,即:當打破元素間的隔離性所付出的代價很小時可以直接打破,又或者分裂組件的額外的工作是否太多。而我要提醒你的是這是個漸進性的工程且一致性是眾多因素中最重要的。只要當你的團隊統一風格而且你把事情做好的時候,你才做了正確的事。
來自:http://www.zcfy.cc/article/8-simple-rules-for-a-robust-scalable-css-architecture-2082.html