本文節選自Tiffany新書《CSS大師,第二版》。我們將探討兩種CSS命名方法論。這兩種方法都是為了改進大型網站和大型團隊的開發流程而創建的;然而,它們同樣適用於單人團隊。您可以選擇其中一種、兩種都不選,或者混合使用,這取決於您自己。介紹它們的目的是幫助您思考編寫自己的CSS的方法。
關鍵要點
BEM,或塊-元素-修飾符,是一種方法論、命名系統和一套相關的工具。 BEM誕生於Yandex,旨在由大型開發團隊進行快速開發。在本節中,我們將重點關注概念和命名系統。 BEM方法論鼓勵設計師和開發人員將網站視為可重用組件塊的集合,這些塊可以混合和匹配以創建界面。塊只是文檔的一部分,例如標題、頁腳或側邊欄,如下圖所示。也許令人困惑的是,“塊”在這裡指的是構成頁面或應用程序的HTML片段。
塊可以包含其他塊。例如,標題塊可能還包含徽標、導航和搜索表單塊,如下所示。頁腳塊可能包含站點地圖塊。
比塊更細粒度的是元素。正如BEM文檔所解釋的:
元素是執行特定功能的塊的一部分。元素依賴於上下文:它們只有在其所屬的塊的上下文中才有意義。
例如,搜索表單塊包含文本輸入元素和提交按鈕元素,如下圖所示。 (為了明確起見,我們使用的是設計元素意義上的“元素”,而不是HTML元素意義上的“元素”。)
另一方面,主要內容塊可能具有文章列表塊。此文章列表塊可能包含一系列文章推廣塊。每個文章推廣塊可能包含圖像、摘錄和“閱讀更多”元素,如下所示。
塊和元素共同構成了BEM命名約定的基礎。根據BEM規則:
塊名稱和元素名稱通常用雙下劃線(.block__element)分隔。塊和元素名稱通常用雙連字符與修飾符名稱分隔(例如,.block--modifier或.block__element--modifier)。以下是使用搜索表單示例的BEM外觀:
<div class="search"> <label for="s" class="search__label">Search for: </label> <input type="text" id="s" class="search__input"> <button class="search__submit">Search</button> </div>
具有深色背景的此表單的變體可能使用以下標記:
<div class="search search--inverse"> <label for="s" class="search__label search__label--inverse">Search for: </label> <input type="text" id="s" class="search__input"> <button class="search__submit search__submit--inverse">Search</button> </div>
我們的CSS可能如下所示:
.search { color: #333; } .search--inverse { color: #fff; background: #333; } .search__submit { background: #333; border: 0; color: #fff; height: 2rem; display: inline-block; } .search__submit--inverse { color: #333; background: #ccc; }
在我們的標記和CSS中,search--inverse和search__label--inverse是附加的類名。它們不是search和search__label的替代品。類名是BEM系統中使用的唯一選擇器類型。可以使用子選擇器和後代選擇器,但後代也應該是類名。元素和ID選擇器是被禁止的。強制執行塊和元素名稱的唯一性還可以防止命名衝突,這在團隊中可能會成為問題。這種方法有幾個優點:
BEM的內容遠不止本章節中的一節所能容納的。 BEM網站更詳細地描述了這種方法,並且還提供了工具和教程來幫助您入門。要了解有關BEM命名約定方面的更多信息,另一個極好的資源是Get BEM。
如果說BEM是行業寵兒,那麼原子CSS就是它的叛逆者。雅虎的Thierry Koblentz在其2013年的文章“挑戰CSS最佳實踐”中命名並解釋了原子CSS,它使用一個緊湊的類名庫。這些類名通常是縮寫的,並且與它們影響的內容脫節。在原子CSS系統中,您可以知道類名是什麼作用——但是類名(至少,樣式表中使用的類名)和內容類型之間沒有關係。讓我們用一個例子來說明。以下是我們在所謂的傳統CSS架構中可能稱之為的一組規則。這些規則集使用描述其應用內容的類名——全局消息框,以及“成功”、“警告”和“錯誤”消息框的樣式:
<div class="search"> <label for="s" class="search__label">Search for: </label> <input type="text" id="s" class="search__input"> <button class="search__submit">Search</button> </div>
要創建錯誤消息框,我們需要將msg和msg-error類名都添加到元素的class屬性:
<div class="search search--inverse"> <label for="s" class="search__label search__label--inverse">Search for: </label> <input type="text" id="s" class="search__input"> <button class="search__submit search__submit--inverse">Search</button> </div>
讓我們將其與原子系統進行對比,在原子系統中,每個聲明都成為它自己的類:
.search { color: #333; } .search--inverse { color: #fff; background: #333; } .search__submit { background: #333; border: 0; color: #fff; height: 2rem; display: inline-block; } .search__submit--inverse { color: #333; background: #ccc; }
這是更多的CSS。現在讓我們重新創建我們的錯誤消息組件。使用原子CSS,我們的標記變為:
.msg { background-color: #a6d5fa; border: 2px solid #2196f3; border-radius: 10px; font-family: sans-serif; padding: 10px; } .msg-success { background-color: #aedbaf; border: 2px solid #4caf50; } .msg-warning { background-color: #ffe8a5; border-color: #ffc107; } .msg-error { background-color: #faaaa4; border-color: #f44336; }
我們的標記也更冗長。但是當我們創建警告消息組件時會發生什麼?
<p class="msg msg-error">An error occurred.</p>
兩個類名發生了變化:bg-d和bc-d被bg-c和bc-c替換。我們重用了五個規則集。現在,讓我們創建一個按鈕:
.bg-a { background-color: #a6d5fa; } .bg-b { background-color: #aedbaf; } .bg-c { background-color: #ffe8a5; } .bg-d { background-color: #faaaa4; } .bc-a{ border-color: #2196f3; } .bc-b { border-color: #4caf50; } .bc-c { border-color: #ffc107; } .bc-d { border-color: #f44336; } .br-1x { border-radius: 10px; } .bw-2x { border-width: 2px; } .bss { border-style: solid; } .sans { font-style: sans-serif; } .p-1x { padding: 10px; }
嘿!在這裡,我們重用了四個規則集,並且避免向我們的樣式表中添加更多規則。在一個強大的原子CSS架構中,添加新的HTML組件(例如文章側邊欄)不需要添加更多CSS(儘管實際上,它可能需要添加更多內容)。原子CSS有點像在CSS中使用實用程序類,但達到了極致。具體來說,它:
但是,原子CSS並非沒有爭議。
原子CSS與我們學習的幾乎所有關於編寫CSS的內容都背道而馳。它感覺幾乎和到處粘貼樣式屬性一樣糟糕。事實上,對原子CSS方法論的主要批評之一是它模糊了內容和演示之間的界限。如果將元素浮動到左側並添加十像素的邊距,當我們不再希望該元素浮動到左側時該怎麼辦?當然,一個答案是將fl類從我們的元素中刪除。但是現在我們正在更改HTML。使用CSS的全部原因是為了使標記不受演示的影響,反之亦然。 (我們也可以通過從樣式表中刪除.fl {float: left;}規則來解決此問題,儘管這會影響每個類名為fl的元素。)儘管如此,更新HTML可能是為了獲得更簡潔的CSS而付出的少量代價。在Koblentz的原始文章中,他使用了諸如.M-10(margin: 10px)和.P-10(padding: 10px)之類的類名。這種命名約定的問題應該很明顯。更改為五像素或20像素的邊距意味著我們需要更新我們的CSS和HTML,否則可能會導致類名無法準確描述其效果。使用諸如p-1x之類的類名,如本節所述,解決了這個問題。類名中的1x部分錶示比率,而不是定義的像素數。如果基本填充是五像素(即,.p-1x { padding: 5px; }),則.p-2x將設置十像素的填充。是的,這不太能描述類名所做的工作,但這同時也意味著我們可以更改CSS而無需更新HTML,並且不會創建誤導性的類名。原子CSS架構不會阻止我們使用描述內容的類名在我們的標記中。您仍然可以向代碼中添加.button-close或.accordion-trigger。對於JavaScript和DOM操作,此類類名實際上更可取。
當您有大量開發人員並行構建CSS和HTML模塊時,BEM效果最佳。它有助於防止大型團隊創建的錯誤和bug。它可以很好地擴展,部分原因是命名約定具有描述性和可預測性。 BEM不僅僅適用於大型團隊,但它非常適合大型團隊。當有一個小型團隊或一名工程師負責開發一組CSS規則,並由一個更大的團隊構建完整的HTML組件時,原子CSS效果更好。使用原子CSS,開發人員只需查看樣式指南——或CSS源代碼——即可確定特定模塊所需的類名集。
在實踐中,您的CSS可能包含多種方法的混合。除了影響佈局的實用程序類名之外,您可能還有一些描述內容或組件的類名。如果您無法完全控制標記(例如使用CMS),那麼這兩種方法都可能沒有用。您甚至可能需要使用冗長且特定的選擇器來實現您想要的目標。
BEM(塊、元素、修飾符)和原子CSS都是組織和構建CSS代碼的方法論。 BEM專注於一種命名約定,使CSS更容易閱讀和理解。它將設計劃分為塊、元素和修飾符,以在CSS和HTML之間創建清晰、嚴格的關係。另一方面,原子CSS是關於編寫反映視覺功能的小型、單一用途的CSS類。它鼓勵可重用性並旨在減少代碼量。
BEM通過在CSS和HTML之間提供清晰而嚴格的關係來提高CSS的可擴展性。它使用特定的命名約定,使理解不同元素之間的關係更容易。這使得代碼更易於維護和擴展,因為更容易添加新功能或修改現有功能而不會破壞任何東西。
是的,可以同時使用BEM和原子CSS。一些開發人員發現,結合這兩種方法可以獲得兩全其美的好處。 BEM的嚴格命名約定可用於構建CSS,而原子CSS的單一用途類可用於設置單個元素的樣式。這種組合可以產生高度組織化和易於維護的CSS代碼庫。
原子CSS提供了許多好處。它鼓勵可重用性,這可以大大減少您需要編寫的CSS數量。它還提高了設計的一致性,因為相同的類用於不同的組件。此外,原子CSS可以使您的樣式表更易於管理和理解,因為每個類都有一個單一、明確定義的目的。
BEM通過鼓勵開發人員使用類選擇器而不是ID選擇器來幫助處理CSS特異性問題。這導致整個項目中的特異性保持一致,因此在必要時更容易覆蓋樣式。此外,BEM的命名約定清楚地表明哪些元素是相關的,從而減少了意外樣式衝突的可能性。
是的,原子CSS適用於大型項目。它對可重用性和單一用途類的關注可以幫助保持CSS的可管理性,即使項目不斷發展壯大。但是,它需要一種嚴謹的方法來確保類保持一致和有意義。
BEM清晰而嚴格的命名約定使團隊成員更容易理解CSS代碼,無論他們何時加入項目。這可以改善協作,因為開發人員可以輕鬆理解和修改其他人編寫的代碼。
原子CSS的一個潛在缺點是它可能導致HTML中出現大量類。這可能使HTML更難閱讀和理解。此外,原子CSS需要一種嚴謹的方法來確保類保持一致和有意義。
要開始實現BEM,您需要將設計劃分為塊、元素和修飾符。然後,使用BEM的命名約定來命名您的CSS類。這將在您的CSS和HTML之間創建清晰的關係,使您的代碼更易於閱讀和維護。
是的,BEM和原子CSS都可以與Sass或Less等CSS預處理器一起使用。這些預處理器可以使管理CSS更容易,並且它們與BEM和原子CSS的組織原則非常契合。
以上是CSS體系結構:Block-Element-Modifier(BEM)和Atomic CSS的詳細內容。更多資訊請關注PHP中文網其他相關文章!