BEMとコンポーネントとCSSの組み合わせで失敗した話

## はじめに
はじめまして！:boy_tone1::boy_tone1:
初めて投稿します、じいやと申します。:older_man_tone1:

最近、WebアプリのUIリニューアルに際して今までのCSSを全て消して、新しいCSSを書くというタスクを担当しました。別のプロジェクトで[BEM](https://en.bem.info/)を一瞬使っていたので、今回も[BEM](https://en.bem.info/)を使ってやってみようと思って進めていきました。

その中で、問題、そして葛藤があったのでそれを書いていこうと思います。

## 背景
普段BEMを書くとするとCSSではなくSassと使用すると思うのですが、今回は背景もありCSSでやることになりました。

思えば、ここでSassを使わないならBEMを使う旨味が薄くなってしまうので冷静になってBEMではないものを考慮するべき、もしくはSassを使うように考えるべきだったのかもしれません。:frowning2:

## BEMとは
BEMを知らない方のために軽く説明すると、BEMとは
 - **Block**
 - **Element**
 - **Modifier**
の頭文字をとったもので、CSSの設計手法です。

BEMではHTMlの要素を細かく分解して、コンポーネントごとにしていきます。
**Block**は親コンポーネント、**Element**は子コンポーネントを指します。
**Modifier**はその要素の特徴を装飾するトッピングのような物です。

これだけだと何を言っているかわからないですよね笑:sweat_smile:
例をあげて説明します。

例えば、フォームを作るとします。
HTMLはこんな感じに

```html:index.html
    <form>
        <label>Email</label>
        <input type="email" name="email"/>

        <label>Name</label>
        <input type="text" name="name"/>

        <input type="submit" value="Submit" />
        <input type="reset" value="Reset" />
    </form>
```

ここにBEMを入れるとすると、まず大きな**Block**としてformがあります。
ですのでとりあえず適当に

```css:main.css
.form {
    max-width: 85%;
    margin: 24px 0;
    padding: 24px;
}
```
とします。
次に、formの中にあるものを見ると```<label>``` ```<input>```ですね。（厳密に言えば```<input>```に入力欄とボタンがあります。）これらは、formという**Block**内の**Element**になります。

**Block**と**Element**はアンダースコア2つで繋ぎます。
ですので、下記みたいにします。:writing_hand:

```css:main.css
.form {
    max-width: 85%;
    margin: 24px 0;
    padding: 24px;
}

.form__label {
    display: block;
    font-size: 1.2rem;
    margin-bottom: 12px;
}

.form__input[type=text],
.form__input[type=email]{  
    display: block;
    width: 100%;
    height: 28px;
    border-radius: 5px;
    margin-bottom: 12px;
}

.form__button {
    display: block;
    background-color: #03fc90;
    width: 80px;
    height: 36px;
    border-radius: 5px;
    margin-bottom: 12px;
}
```

いい感じです。
最後に、**Modifier**です。これは、要素を修飾するものです。今回はリセットボタンをグレーにしましょう。(これに関してはいくつか書き方があると思いますが、CSSを使っていて```.form_button```のcssを継承したいので下記のようにしました。)

```css:main.css
~~
.form__button {
    display: block;
    background-color: #03fc90;
    width: 80px;
    height: 36px;
    border-radius: 5px;
    margin-bottom: 12px;
}

.form__button.--gray {
    background-color: #d9d9d9;
}
```

クラスをそれぞれのタグにつけたのが以下です。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="ryojik74" data-slug-hash="yLyJGEd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="yLyJGEd">
  <span>See the Pen <a href="https://codepen.io/ryojik74/pen/yLyJGEd">
  yLyJGEd</a> by RyojiK74 (<a href="https://codepen.io/ryojik74">@ryojik74</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


とてもCSSが整っていて、わかりやすいですよね:sunny::sunny:
CSSを見ただけでなんとなくどこに使われているかがわかります。

## 問題はここからだぁ！！:fist::fist:
急にテンションが高くなりましたが、ここから複雑になってきたのです。
まず僕たちは、デザイナーから受け取ったデザインを見てみました。するとそこには、同じスタイルをもつコンポーネントが多くありました。まあとりあえずページを作ってみて、共通化できるところはしていこうということで進めていきました。:scissors:
1ページ目(使い回し)

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="ryojik74" data-slug-hash="yLyJGEd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="yLyJGEd">
  <span>See the Pen <a href="https://codepen.io/ryojik74/pen/yLyJGEd">
  yLyJGEd</a> by RyojiK74 (<a href="https://codepen.io/ryojik74">@ryojik74</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

次のページを見ると同じボタンが今度は```<form>```内ではなく、リンクとして使われていました。
とりあえずさっきのクラスを使いまわそうとしました。
2ページ目

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="ryojik74" data-slug-hash="PowzXXa" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="another_page">
  <span>See the Pen <a href="https://codepen.io/ryojik74/pen/PowzXXa">
  another_page</a> by RyojiK74 (<a href="https://codepen.io/ryojik74">@ryojik74</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


見た目は悪くない...だけど、これHTMLをよく見るとわかると思いますが、```contact```というブロックなのに```form__button```が存在してしまっている...。うーん、ビミョい...。:sweat:

でも、ボタンのスタイルを一括で変えたいというタイミングがこれ以降であるかもしれないことを考えると同じスタイルだが別の名前を持つ物を作るのは避けたい...。
泣く泣く、ボタンコンポーネントは例外として、```.content-button```というクラスを作ってしまいました。:robot:
いや、これSassだったら```@extend```つかってもっとスマートに```button```継承しながらかけるのに...。

なんやかんや、```.content-button```のおかげで一応作業を進められるようになった我々を待ち構えていたのは```margin-bottom```君でした。

## レイアウトとコンポーネントの狭間

次のページでも、同じボタンが使われていましたが 一つ違いがありました。それは、彼だけ**```margin-bottom: 36px;```**だったのです。
今まで、12pxだったから甘えてきたものの3倍の36pxはきついものがありました。
**というかそもそもコンポーネントで設計する場合はmarginなどのレイアウトに関わる部分はつけるべきではありません。**つけてしまうと、このように再利用性が著しく下がってしまいます。

正直詰みの状態でした。:frowning2::frowning2:
BEMの見やすさやメンテナンス性を保持しようと考えると```--mb-24```みたいな汎用クラスを作成はしたくないですし、かと言ってCSSのメンテナンス性を踏まえるとクラスを分けたりしたくはありません。最終的に僕らはプロジェクトのエンジニアリーダーに話しをして、タグに直接styleを埋め込むもしくはページのheadにstyleを埋め込み、そこで各ページに必要なmarginなどを書くことでとりあえず落ち着きました。:gear:

## まとめると問題はなんだったのか??
Sassの```@extend```がないCSSでメンテナンス性とBEMの両立をしようとしたのが無謀だったのだと思います。
使うフレームワークによるとは思いますが、BEMを使い、さらにコンポーネントを作ってそのメンテナンス性をあげる場合はSassを使わない手はないと思います。

もっと設計の段階でいろいろ見越して考えるべきだったと後悔しています。:sob:

僕とは違いみなさんは先のことをきちんと考えてから導入されているかもしれませんが、これからBEMを考えてみようと思う方に届けばいいなと思います。

ここまで読んでくださりありがとうございました:older_man_tone1: