2023-07-14|閱讀時間 ‧ 約 8 分鐘

BEM 設計模式與各種使用情境

    所有的 CSS 設計模式都是為了維持可讀性、好維護、易擴充這幾個目標,今天就來談談 BEM 設計模式,並搭配 Sass 中的 SCSS 來介紹,並探討在各種情境下該如何使用 BEM。

    先說說 BEM 有哪些好處:

    1. 從 Class 命名可以馬上看出結構之間的相依性

    2. 避免 Sass 過多嵌套的問題(一般來說最多是三層)

    3. 適合任何大小專案

    初期使用應該會覺得命名很痛苦,或是覺得命名很長長長,後面這個問題已經可以透過 SCSS 引用父選擇器& 解決,前者的話就只能多寫幾次熟悉了。接下來正式介紹 BEM。

    BEM 主要由三個概念組成

    • Block 區塊:限定了樣式的作用域,本身通常不會寫入樣式設定
    • Element 元素:需要綁定在區塊底下,使用兩個下底線 __ 將區塊和元素名稱連接,例如 .banner__title
    • Modifier 修飾器:用來修飾區塊或是元素的樣式,和 Element 一樣,不能獨立存在,需要使用兩個減號 -- 與區塊或元素名稱連接,例如 .banner__title--big 或是 .title--primary

    範例如下,可以看到區塊為 banner,並有三個元素從屬於 banner 區塊:

    <div class="banner">
    <h2 class="banner__title">標題</div>
    <h3 class="banner__subtitle">子標題</div>
    <div class="banner__img"><img src="banner.jpg" alt="banner" /></div>
    </div>

    BEM 規範

    • 一律使用 class 選擇器
    • 不要過度模組化,需要拿捏模組的深度
    • 區塊和元素的命名有兩個單字以上時可使用小駝峰或 -

    關於最後一點,筆者為了可讀性,較傾向使用小駝峰,畢竟 BEM 裡面有較多的 -- 和 __,假如又額外加入了一些共通樣式的 class,例如命名為 .text-center,乍看還需要分辨裡面的 - 是拿來連接單詞,還是用來描述 class 用途。

    Block 區塊

    以功能性來命名,例如 .navbar, .card 等等,且具有唯一性,一般不會寫入樣式,Block 裡面可以再包其他 block,可以存在於頁面任何一個地方。

    Element 元素

    不能獨立於區塊之外,以目的來命名。

    Modifier 修飾器

    可以針對區塊或是元素做樣式微調,Modifier 絕對不能單獨存在,他必須和相關的區塊或是元素一起出現,經常用於調整大小、顏色、狀態等等。

    <div class="banner banner--small">
    <h2 class="banner__title banner__title--big">標題</div>
    <h3 class="banner__subtitle">標題</div>
    <div class="banner__img"><img src="banner.jpg" alt="banner" /></div>
    </div>

    假如樣式可以單獨存在,就應該直接獨立成一個 class ,供網頁中所有元素視情況使用,例如 .hidden 就可能是專門用來將某個元素隱藏,並不屬於任何一個區塊。

    Modifier 不適合用在狀態變化

    這篇文章中有提到 BEM 的 Modifier 不適合用在狀態變化,狀態變化舉例像是按鈕按下去之後會變換樣式,該文章作者建議可以使用 SMACSS 概念代替,例如使用 .is-closed.is-open 的命名。

    我認為這個作法不只是為了簡潔、可讀性,也有可能是因為狀態變化經常需要和 JS 做搭配,如果名稱取得太長,會導致取得 DOM 元素時的語法也會跟著很長,從而影響 JS 易讀性降低。

    情境題

    Q1. 只有兩層當然容易命名,那如果到第三層呢?

    建議 BEM 只能一個區塊對應一個元素,也就是不允許使用兩組下底線來標示從屬關係,例如 .card__body__title 就打破了這個規則,在這邊提供兩個寫法參考:

    寫法一:使用減號連接

    <ul>
    <li class="card">
    <div class="card__head">
    <h2 class="card__head-title"></h2>
    </div>
    <div class="card__body">
    <h3 class="card__body-title"></h3>
    </div>
    </li>
    </ul>
    card{
    &__head{
    ...
    &-title{
    ...
    }
    }
    }

    寫法二:如果結構比較簡單,只有單一、但很多層,也可以只寫和最大區塊的從屬關係

    <nav class="nav">
    <ul class="nav__list">
    <li class="nav__item">
    <a href="nav__link"></a>
    </li>
    </ul>
    </nav>
    .nav{
    &__list{
    ...
    }
    &__item{
    ...
    }
    }

    Q2. 如果真的結構有很多層、又很複雜,或是寫入了太多的 Modifier 導致易讀性降低怎麼辦?

    建議能拆成一個區塊的就拆出來,最後再把它們組裝起來,就能避免結構過多的問題,寫 BEM 時很重要的一點是結構深度要拿捏好,不要寫得太深入。

    Q3. 當兩個區塊混合時,該如何撰寫才不會覆蓋樣式或是造成混亂?

    如果某個區塊在另一個區塊裡面時,樣式有些微不同,可以使用 Modifier 寫法避免搞混,範例中的 .nav--inside-footer 就是專門為 footer 裡的導覽列區塊特別設定的樣式。

    <footer>
    <ul class="nav nav--inside-footer">
    <li class="nav__item">
    <a href="#" class="nav__link"></a>
    </li>
    <li class="nav__item">
    <a href="#" class="nav__link"></a>
    </li>
    </ul>
    </footer>

    Q4. 如果我想針對一些頁面中的常見樣式做設定,它並不屬於任何一個結構,該如何撰寫?

    有時不用太過遵守 BEM 規則,網頁中並不是所有內容都會用上 BEM,某些常用設定可以直接成為一個單純的 Class,例如 .clearfix;或是透過一些標記,清楚知道這是一個全域的樣式設定,例如 .g-clearfix,在前面加入的 g 代表 global,表示這是一個全局樣式。 

    參考文章


    有關 BEM 設計模式的分享就到這裡,若有錯誤歡迎指正,感謝看完這篇的大家。

    分享至
    成為作者繼續創作的動力吧!
    從 Google News 追蹤更多 vocus 的最新精選內容從 Google News 追蹤更多 vocus 的最新精選內容

    傑米的沙龍 的其他內容

    你可能也想看

    發表回應

    成為會員 後即可發表留言
    © 2024 vocus All rights reserved.