技術部システム開発課の田畑です。よろしくお願いします。
今回はCSS設計手法であるBEMについて書きたいと思います。
最近はBEMを使ってCSSを記述していた(つもり)だったのですが
- 自己流でやってしまっていた部分があった
- BEMの目指すところは何か理解が足りなかった
という理由からBEMをもう一度学習しなおすことにしました。
今回学習をすすめるにあたり、以下の本を参考にしました。 具体例が多くとても分かりやすかったのでおすすめいたします。
なぜBEMを使うのか
シナプスのホームページは共通CSSとページ別のCSSを読み込ませることでスタイル指定を実現しています。 ところがページ数が大変多く、長年運用しつつページを継ぎ足しながらやってきたため、CSSの数も多くなり以下のような問題が発生しております。
- スタイルの優先順位が複雑に絡んでおり思い通りにならないことがある
- 別の場所に流用すると表示が崩れる
- 制作者にしかわからないクラス名
- 制作時期によって違う記述方法
- 使いまわしがしづらいスタイル指定
この問題を解決するためBEMというCSS設計手法をとりいれることになりました。
BEMとは
BEMとは、Block、Element、Modifierの略語です。Webサイトのコンポーネント化のためのフロントエンド設計方法のひとつで、厳格なクラス名の命名ルールが特徴的な手法です。
引用:BEMによるフロントエンドの設計 | 第1回 基本概念とルール | CodeGrid
それぞれの役割は以下のようになります。
Block
使いまわせるパーツ・モジュール。 独立性を保持するため、レイアウトに関する指定はしないこと。 見た目ではなく「何のためにつかわれるのか」を表す命名をする。
Element
Blockを構成しているもの。Block外では独立して使えない。 Block内での構成が変わる可能性があるのでElementの中にElementをネストしない。
Modifier
BlockやElementの状態や見た目を定義する。 Modifierは単独で利用することはできない、BlockかElementのクラスがある状態で使う。
このルールに則り記述していくことで、前述の問題が解消されることが期待できます。
BEMの記述方法
classの書き方
Block、Element、Modifierのそれぞれの区切りに一貫したセパレーターを使います。
block__element--Modifier
※上記はMindBEMdingの命名規則です。シナプスではこちらを使っていきます。
- BlockとElementの区切りはアンダースコア2つで繋げる
- BlockもしくはElementとModifierの区切りはハイフン2つで繋げる
- Block、Element、Modifierを2つ以上の単語で表す場合の単語と単語の区切りはハイフン
- Modifierのキーは省略可能
Mixについて
HTML要素に異なる複数のクラスをつけることで、複数のスタイルを付与することができます。 「Blockに指定したいスタイル」「Elementに指定したいスタイル」を分離して組み合わせて適用できるので、再利用性を高めることができます。
良いCSSが目指す4つのポイント
良いCSS(BEMなど)が目指していることは何かというと、この書籍の中で以下のことがあげられていました。
- 予測できる
- 再利用できる
- 保守できる
- 拡張できる
引用:CSS設計完全ガイド ~詳細解説+実践的モジュール集:書籍案内|技術評論社
つまり
- スタイリングが期待通りに動く、意図しない場所に影響を与えない
- コードが使い回せる
- 新しい機能を追加したときに影響を与えたり、壊れたりしない
- ルールがしっかり決まっており複数人で管理ができる
ということだそうで、今CSS設計で困っている部分をうまく解消できそうです!
CSS設計の8つのポイント
では実際にどのようなことに気を付けて設計していくかというと、以下の内容になります。
- 特性についてCSSを分類
- HTMLとスタイリングが疎結合である
- 影響範囲がみだりに広すぎない
- 特定のコンテコストにみだりに依存しない
- 詳細度がみだりに高くない
- クラス名から影響範囲が想像できる
- クラス名から見た目・機能・役割が想像できる
- 拡張しやすい
引用:CSS設計完全ガイド ~詳細解説+実践的モジュール集:書籍案内|技術評論社
具体的には
- HTMLの要素名をセレクターとして利用しない。
- スコープを絞って影響範囲を狭くする。
- 利用場所を変えたらスタイルが効かなくなるのを避ける。
- idをスタイルに利用しない。クラスセレクターを使う。
- HTMLの影響範囲がCSSのスタイリングと一致する。
- 影響範囲が想像できるクラス名をつける。
- マルチクラス設計を使う。
などに注意してコーディングしていきます。
コーディングしてみる
では実際にシナプスホームページ内の組織向けページのコンテンツ部分をBEMでコーディングしてみます。
まずはページを構成する要素を内容ごとにブロックに分けます。
- 役割が想像できる名前を利用する
を念頭に置いて名前をつけていきます。
これをHTMLで書き出した後、CSSで整えていきます。
HTML
<div class="content content--column"> <main class="main content__main"> <div class="main__inner"> <h1 class="title">組織専用メニュー</h1> <div class="pr-banner pr-banner--center"> <p class="pr-banner__text">法人向けモバイルサービスAcrobizMobile お客様の~即日利用OK!</p> <img class="pr-banner__img" src=""> </div> <div class="service-intro service-intro--recommend"> <h2 class="service-intro__title">ご利用シーンに合わせたおすすめのサービス</h2> <ul class="service-intro__list"> <li class="service-intro__item">1.独自ドメイン導入&複数拠点インターネット接続</li> <li class="service-intro__item">2.VPN導入&複数拠点で社内サーバー共有</li> </ul> </div> <div class="service-intro"> <h2 class="service-intro__title">独自ドメインサービス</h2> <ul class="service-intro__list"> <li class="service-intro__item">ホスティング・プラス</li> <li class="service-intro__item">ホームページ改ざん検知サービス</li> </ul> </div> </div> </main> <aside class="side content__side"></aside> </div>
CSS
.content--column{display: flex;} .main__inner{margin: 15px;} .pr-banner--center{text-align: center;} .pr-banner__text{margin: 10px;} .pr-banner__img{ border: #a8a8a8 1px solid; margin: 10px; } .main { width: 766px; border: 1px solid #a8a8a8; box-shadow: 1px 1px 1px rgb(0 0 0 / 20%); } .side {width: 231px;} .title{ font-size: 2em; color: #ff8000; margin-bottom: 2em; padding: .5em; border-top: 1px dashed #999999; border-bottom: 1px dashed #999999; } .service-intro--recommend .service-intro__title{ margin: 10px auto 15px auto; color: #FFFFFF; font-weight: normal; padding: 5px 0 5px 15px; border-left: solid 7px; background-color: #336600; border-color: #568A0F; } .service-intro--recommend .service-intro__list{ display: flex; width: 80%; margin: 0 auto 15px auto; } .service-intro--recommend .service-intro__item{ list-style-type: none; background-color: #DAF0D2; width: 45%; display: block; margin-bottom: 30px; margin-right: 5%; padding: 10px; background-position: 95% 50%; border: solid 1px #92C459; } .service-intro--recommend .service-intro__item:last-child { margin-right:0; border-bottom: solid 1px #92C459; } .service-intro__title{ margin: 10px auto 15px auto; color: #FFFFFF; font-weight: normal; padding: 5px 0 5px 15px; border-left: solid 7px; background-color: #2F48A1; border-color: #3986DB; font-size: 1.3em; } .service-intro__list{ width: 80%; margin: 0 auto 15px auto; } .service-intro__item{ border-bottom: dashed 1px #777777; padding: 10px 0; list-style-type: none; } .service-intro__item:last-child {border-bottom:none;}
以下のようなことに気を付けて設計しました。
- idではなくclassで指定する
- pr-banner、service-introなど役割が想像できる名前を利用する
- 影響範囲が想像できるクラス名を付ける
service-intro__title service-intro__list
など
- service-introのMix(service-intro--recommend)を作成、サービス紹介の中からおすすめとして取り上げているブロックのデザインを変える
- contentのMix(content--column)で左右にカラムをわけた
- HTMLの構造に依らないクラス名にした
service-intro__list service-intro__item
など
上記の内容は組織向けページのみを見て設計したものになります。 そのため全体的な構成を考えて設計した場合には、違ったものになる可能性もあります。
まとめ
今回シナプスの組織向けページを設計してみて、実際にコーディングしてみると迷う部分が多々あり難しいなと感じました。迷わず設計できるようになるにはしばらくかかりそうです。 BEMを導入することで綺麗なCSSを維持できるようにしていきたいです。