フロントエンドエンジニアになりたい

デザイナーなのかコーダーなのかディレクターなのかよくわからない人のブログ。趣味で絵を描きました(過去形)

モダンCSS設計での失敗メモ

現在担当しているサービスでSassを使ったBEMの設計を行いました。 当初これでモダンですばらしいコーディングがスタートすると思っていたのですが、 世の中そんなに甘くはなく、また、僕が未熟なこともあり設計上の失敗をいくつか犯してしまったので、今後の自分への戒めの意味も含めて書き留めておこうと思います。

BEMでBlockの2階層以上の表現

当初 .Block__Element__Block__Elementのようにブロックのネストを行っていたのですが、すぐにこれはまずい設計であることに気付きました。

まず、HTML要素がとても見辛くなってしまう。 (ただでさえBEMは見にくいHTMLになってしまうのに。。。)

次にSassですが、非常にネストが深くなってしまい、 今どの階層にいるのかわかりづらくなってしまいました。 また上位のModifierによって子供のBlockに変化をつけたい場合、 連結し続けていると .Block__Element--Modifier__Blockのようになってしまいます。

...ではこのような場合どうするのがいいかというと、 .Block__Element .Block__Element というように単純に分けてしまった方が楽です。 これはたとえ子供のBlockが親のコンポーネントとして単体では独立しえなくてもです。

そのコンポーネントの中でしかスタイルが定義されていないものをBlockと定義するのは なにか気持ち悪く思いますが、子供のBlockはいろんなコンポーネントに内包されることによって、 さまざま変化がするような抽象的なものとして定義するのが良いのではないかと思いました。

// 単体では使わない抽象的な画像とキャプションのスタイル
.figure {
   &__image {
   }
   &__caption {
   }
}

// 画像リスト
.list {
  &__item {
    // 画像リストの中のイメージ
    .figure {
      &__image {
      }
      &__caption {
      }
    }
  }
}

// 記事
.article {
  &__body {
    // 記事の中のイメージ
    .figure {
      &__image {
      }
      &__caption {
      }
    }
  }
}

ModifierとSMACSSのStateの併用

BEMでシングルクラス設計をするとCSS側が冗長になりがちです。 そこでマルチクラス設計を行うことにしました。 その時に、Modifierだと簡単な状態を表す時なんかに.Block__Element .Block__Element--activeみたいに ちょっと長くなりすぎるなと思ったのです。 そこでどこかの記事を参考にして、SMACSSのStateを併用することにしました。.Block__Element .is-activeみたいな感じです。

当初、Blockのもっと根本的なバリエーション違いなんかを表す場合にModifier、 簡単な状態の変化をつける場合にはStateと住み分けをしようと思ったのですが、 やっているうちに、結局そこまで厳格に運用することが難しく、どちらかだけでいいなと思いました。

抽象的なものと具象的なおのでファイルを分けなかった

これはどういうことかというと、プレースホルダセレクタやミックスインのような単体では出力しないものと、 出力するコンポーネントを同じファイルに混ぜてしまったということです。

大規模なサイトの場合、ページごとに個別のスタイルファイルを使用したい場合がよくあると思います。 そこで例えばリンクフォントの定義のセットをそこに適用したいなぁ...というときに

%link-color-hoge {
  &:hover {
  }
  &:active {
  }
}

こんな感じのがあると便利かなと思います。しかしこれを共通フォント定義と出力を行っている base.scssのようなものの中につっこんでしまいました。

body {
  font-family: hogehoge...;
}

%link-color-hoge {
  &:hover {
  }
  &:active {
  }
}

その結果、1つのCSSファイルだけ生成するようなサイトの場合はいいのですが、 共通CSS + 個別ページCSSの2つを読み込むような場合で、 個別ページCSSでこのプレースホルダセレクタを使いたいなと思った場合に@importしてしまうと、 共通フォントの出力の部分が2重に上書きされてしまうことになります。 これはとても初歩的な設計ミスでした。。。

依存関係にある複数CSSを読み込んでスタイルを組み立てる場合、 しっかりとそれを前提に設計をしておくことが大切だと思います。