天天看點

使用 BEM 來子產品化你的 CSS 代碼

<b>本文講的是使用 BEM 來子產品化你的 CSS 代碼,</b>

<b></b>

如果你對 BEM 不熟悉,它是通過一種嚴格方式來将 CSS 類劃分成獨立構成要素的一種命名方法。它表示為 Block Element Modifier,一個常見的 BEM 看起來就像這樣:

BEM 的原則很簡單:一個 Block 代表一個對象_(一個人、一個登入表單、一個菜單);一個 Element 是一個塊中作為特定功能的元件(一個幫助按鈕、一個登入按鈕、一個菜單項);一個 Modifier 是我們如何表示塊或元素的不同變化(一個女人、一個帶有隐藏标簽的迷你登入框、 footer 中一個不同的菜單)_。

使用 BEM 來子產品化你的 CSS 代碼

在我們決定使用 BEM 方法轉換樣式之前,我們做了一些調研。環顧四周,我們發現有不少文章、研究、文檔以及其他一些内容看起來回答了所有可能的問題。顯然我們找到了我們的新死黨。

但是一旦你在某一個方向深入一下,你就會産生一些困惑。你越是努力的想讓它變好,它就變得越糟——除非你對它視而不見,并且把它當作你的朋友來對待。我們的故事開始于幾個月前,那個時候我們遇見了 BEM。我們出去并自我介紹,然後被BEM誘惑到了,我們在的一些玩具項目中使用了 BEM。我們關系很密切,這就産生了一個決定:我們喜歡它,并想進一步發展我們之前的友誼到一個新的高度。

接下來的過程是相當的簡單和自然。我們實驗了一些_命名規範_和_手動建立樣式類_。在決定了_一套準則_後,我們建立的基本的 mixins 來_生成類名_,這樣我們在添加一個新的修飾符或者元素的時候,就不需要每次都是用一個塊名。

是以我們的旅程就像下面這樣開始了:

使用 BEM 來子產品化你的 CSS 代碼

然後我們使用了一系列自定義的 mixins 來轉換上面的代碼:

使用 BEM 來子產品化你的 CSS 代碼

慢慢地,當越來越多的邊緣 case 湧現出來的時候,我們通過增加 mixins 而不同改變已存在的代碼。相當的簡潔!

是以如果我們想定義 full-size 修飾符下的 list 元素,我們需要這樣做:

使用 BEM 來子產品化你的 CSS 代碼

我們并沒有一下子把所有東西都轉換成遵循這些方法,而是平滑地慢慢地把一個一個小塊轉換過去。

與任意規則類似,我們必須了解雙方的關系才能更好的相處。毫無疑問,我們遵循的一個指導原則是 BEM 方法的一部分,其中有一些規則是我們在後來增加的。

基本原則是我們絕不在塊中嵌套塊、在元素中嵌套元素。這是我們絕對不能打破的一條原則。

下面這樣是一個塊中非常深的嵌套:

另一個規則是轉換元素為塊。遵循規則1,我們将任何事情劃分為更小的部分。

讓我們來聊聊一個相關元件的結構:

<a href="https://camo.githubusercontent.com/c0e0bb4664c0ee73c12b31b69f2df568fb6100d4/687474703a2f2f7777342e73696e61696d672e636e2f6c617267652f30303553694e78796777316633646a776d7a3877386a33306a653033787765692e6a7067" target="_blank"></a>

首先我們建立較進階别的塊對應的結構:

使用 BEM 來子產品化你的 CSS 代碼

然後我們成重複較小的内部結構:

使用 BEM 來子產品化你的 CSS 代碼

如果名稱變得更加複雜,我們隻需要把它提取到另一個較小的塊中:

使用 BEM 來子產品化你的 CSS 代碼

然後增加一些複雜的東西——我們想增加一些滑鼠懸浮的效果:

使用 BEM 來子產品化你的 CSS 代碼

所有的這些做完之後,如果我們将代碼放到樣式表中,它看起來結構會很好:

使用 BEM 來子產品化你的 CSS 代碼

沒有什麼能夠阻止我們去清除一些不必要的語義。因為我們這部分代碼明顯是清單的一部分,并且在相關的環境中沒有其他項,是以我們把它重命名為 correspondence-item:

使用 BEM 來子產品化你的 CSS 代碼

這是另外一條規則:我們使用簡化的命名方式來命名嵌套元件的 BEM 塊,進而使其與其它塊不會沖突。

例如,我們不會對 item-title 簡化,因為我們在主要的塊或者預覽的标題中有一個 correspondence-title。這太常見了。

我們使用的 mixins 是一個内部樣式庫 Paint 的一部分。

_Paint 是一個可用的 bower/NPM 包,并且它正在經曆一個核心的重構。BEM mixins 仍然是可用并且定期維護的。_d

我們的目标是使 CSS 類生成系統變得非常簡單,因為我們知道前端和後端工程師不需要花費大量的時間來建構樣式表。是以我們盡可能的自動化這一過程。

同時我們開發了一系列輔助元件來做與模版類似的事情——提供一個定義塊、元素和修飾符的方式,然後就像我們在 CSS 中一樣自動生成标簽類_。_

我們有一個 _bem-selector-to-string 函數來簡單的處理選擇器,将它轉換為字元串。Sass (rails) 和 LibSass (node) 在處理選擇器字元串的時候似乎是不通的。有時類名中的點被添加到了字元串,是以我們要確定在近一步處理之前,要除去這些東西來作為預防措施。

我們用來檢查一個選擇器是否有一個修飾符的函數是 _bem-selector-has-modifier。如果存在修飾符或者有僞類 (:hover, :first-child etc.) 存在,它将傳回 true。

最後一個函數用來從一個包含修飾符或者僞類的字元串中提取塊的名字。如果**對應的塊名全部通過的話,_bem-get-block-name** 将傳回 對應的塊名。當我們使用内部修飾的元素的時候,我們需要使用塊名,否則我們将很難生成一個類名。

bem-block mixin 生成一個帶有類名和相關屬性的基本塊名。

bem-modifier mixin 生成一個 .塊名 — 修飾符 類名。

bem-element mixin 做了更多事。它檢查是否父級選擇器是否是一個修飾符 (或者是一個僞類選擇器)。如果是的話,它将生成一個嵌套的結構包括 塊名 — 修飾符 的塊名,并且在内部包括 塊名 - 元素名。如果不是的話,我們将直接建立一個 塊名__元素名。

對于元素和修飾符,我們目前使用 @each &lt;script type="math/tex" id="MathJax-Element-2"&gt;element in&lt;/script&gt; elements 但是我們在下一個版本中優化了它,進而允許共享相同的屬性來取代在每個元素中複制屬性。

在一個元件中添加了太多的邏輯是非常難重構的。通過使用 BEM 而沒有了太多的選擇,在在大多數時候也是一件好事。

當我們看 DOM 的時候,會很容易的找到塊所在的位置,元素的含義以及修飾符如何使用。類似的,當我們看一個元件樣式表的時候,你會很容易的找到需要改變或者增加一些複雜度的地方。

使用 BEM 來子產品化你的 CSS 代碼

一個具有互動元件的塊結構:

使用 BEM 來子產品化你的 CSS 代碼

一個帶有元素和修飾符的塊結構。

在同樣的樣式表上一起工作,很難避免樣式的沖突。但是通過使用 BEM,每個人可以在他們自己的塊-元素中工作,是以不會影響到其他人。

當寫 CSS 的時候,我們喜歡遵循一系列的原則/規則。BEM 預設遵循下面的規則,進而使的書寫代碼更加容易。

1. 關注度分離

BEM 強制我們劃分樣式為更小的部分,進而使的包括元素和修飾符的塊更易維護。如果邏輯變得太複雜,這時候應該将它劃分到為更小的部分。規則 #2。

2. 單一職責原則

每一個塊有單一的職責來封裝元件中的内容。

對于初始示例,相應的部分應該負責建立清單和預覽元素的網格。我們不共享内部與外部的職責。

遵循這個方法,如果網格發生變化, 我們隻需要改變相應部分的内容。其他的部分仍然可以很好的工作。

3. DRY(不要重複自己)

每次我們偶然發現代碼複制了,我們就會将它提取到占位符和 mixins 中。如果我們需要在目前作用于中 (上下文中重要的元件)重複,那就用這個模式——使用下劃線定義 mixins 和僞類。

記住不要在在用過就丢棄的代碼以及獨立偶爾有不同屬性的兩份重複代碼中浪費功夫。

4. 開閉原則

當使用 BEM 的時候,這個原則是很難打破的。它指出,一切事情都應該對擴充開放,對修改關閉。我們避免直接在其他塊的環境中改變塊的屬性。相反我們建立修飾符來達到這個目的。

BEM 是一個強大的方法,但是我認為這個秘密你是自己的。如果有時候它不起作用,那就找出怎麼才可以起作用,并且可以破壞規則。隻要它能帶來結構和提高生産力,那麼實作它就絕對具有價值。

我們很樂于聽到你使用 BEM 來解決你所面臨大挑戰。

<b>原文釋出時間為:2016年06月12日</b>

<b>本文來自雲栖社群合作夥伴掘金,了解相關資訊可以關注掘金網站。</b>