「ざっくりつかむ CSS 設計」を 2,023 年 10 月 15 日に読んだ。
目次
- メモ
- 著者について p4
- p5
- 3. HTMLとCSSの連携の難しさ p3
- p7
- CSS 設計方法論 p12
- 壊れやすいCSS p12
- p14
- BEM とは p15
- コンポーネントって何? p16
- Block の定義 p27
- なるほど? ではどうやってBlockを考えよう p28
- p29
- Elementって何? p36
- p37
- p39
- p46
- Element in Element はナシ p47
- Modifierって何? p47
- アッパーキャメルケースが好き p55
- p57
- Blockという単語についての補足 p58
- SMACSS p59
- normalize.css のアプローチ p63
- Base ルールを設計しよう p67
- p68
- Layout ルールのコード例 p72
- idセレクタを使うべきか p73
- p74
- BEMっぽくレイアウトを定義する p75
- p83
- !important p95
- p96
- p100
- 3. ルールのカテゴライズを示す文字列 p106
- 余白の問題というのはどういうことか p111
- p117
- p131
- 実装方法3: 余白用のユーティリティクラスを用意する p135
- margin の相殺は使わない p136
- HTMLとCSSを書く人に求められることの難しさ p147
- Atomic Design p148
- ウォーターフォールとは p148
- スタイルガイドとはこういうもの p153
- ただのテキストファイルでよい p158
- 超単純コンポーネント一覧 p159
- コンポーネント一覧の何がありがたいか p161
- コンポーネント一覧を前提としたコーディングの流れ p162
- 雛形を先に作って効率アップ p163
- コンポーネント一覧の更新漏れを防ぐ p163
- コンポーネント一覧のメンテナンス p164
- どこまでスタイルガイドを作り込むべきか p167
- SCSS syntax か Sass syntax p190
- 第 20 回 ビルドしてCSSを作る: Autoprefixer p197
- PostCSSとは p204
- cssnano p206
- p220
- 名前空間的接頭辞 p221
- コードが重複してもよいのか p221
- 入れ子 Block にすべきか否か p230
- p232
- p234
- p239
- HTMLとCSSでコンポーネント化しない p244
- HTMLとCSSの外側でコンポーネント化する p246
- 実装の要件は適切か p252
- おわりに p255
メモ
著者について p4
著者である高津戸壮 (@Takazudo) は、先述の通り、株式会社ピクセルグリッドに属している。
本書執筆時点では、約15年ほどWebサイト制作/アプリケーション開発の現場に身を置いている。
その経歴の半分以上の時間を、 HTML/CSS/JavaScript のコーディングに費してきた。
コーポレートサイトを中心とした多数の Web サイトのコーディングを行い、
その後、 JavaScript を技術の土台に置いたWebアプリケーション開発を多数経験し、
現在はディレクター的な役割として動いていることが多い。
そんな著者は、実は、執筆時点では業務上、自分でCSSを書いていない。
本書の企画アイデアが出たのも、もう何年前のことだっけ……というぐらいのスローペースで本書は書かれた。
しかし、そのように年月が経っても、自分の持っている考え方は依然として重要であり、
新しいメンバーが自分の会社に加わったら知っておいてほしい考え方であると考えたため、一冊の書籍として完成させることにした。
p5
そういう時代において、要件に応じてどういう構成でCSSを書いたらよいのかという判断は、筆者としてはかなり難しいと考えている。
CSSをどう書いたらいいか、どういうツールを選んだらよいのかという問題は、シンプルではないのだ。
別に、1人でCSSを書いているのであれば、好きにすればよいと思う。
どうしようと自由だが、チームで開発を行ったり、末永く、運用のコストを高めないようにサイトを運用していきたいのであれば、
CSSをどういう風に書いたらよいのかという知識はかなり重要なものになる。
3. HTMLとCSSの連携の難しさ p3
HTMLとCSSには別々の役割がある。
HTML は文書構造を定義するもの
CSSは見栄えを定義するもの
HTMLでは文書構造を表現する。
表示するコンテンツの内容を理解しつつ、それらをマークアップする要素を一つひとつ選んでいく必要がある。
これに対しCSSでは見栄えを定義していく。
ブラウザに表示される描画結果を想像しながら、その結果を得るためにはどのようなスタイルを各要素に当てればよいかを考える。
CSSは、その他にアニメーションだったりインタラクションだったり、
まとめるとプレゼンテーションを記述する役割だと言えるが、ややこしいので本書では単純に「見栄え」と呼んでいくことにする。
さて、この役割分担のことは「関心の分離」とか呼ばれたりする。
しかし、これってそんなに単純にいくか?
筆者はそうは思わない。
p7
「私は一人でいつも仕事をしているので関係ないよ」と思う方もいるかもしれないが、
ある程度以上の規模のサイトであれば、この問題を無視するわけにはいかない。
一緒にコードを書いていくためにはどうしたらいいのかを考えることのできる能力が必要になる。
そんなこんなで、チーム開発は難しい。
これが5つ目の難しさ。
CSS 設計方法論 p12
じゃあどうやってCSSを書いたらよいのかな?
そんな疑問に対して、こう書いたらよいぞという考え方をまとめたものが世の中にはいくつもある。
それらは CSS 設計方法論 (CSS methodology) と呼ばれる。
CSS設計方法論を知っていると、このような問題を回避することができるかもしれない。
壊れやすいCSS p12
この「CSS 設計方法論」という言葉が使われだしたのはおそらく2009年頃からだろう。
当時 Yahoo! に在籍していた Nicole Sullivan 氏が発表した、
Object Oriented CSS (OOCSS) というプレゼンテーションの中で語られている考え方が、CSS設計の方法として、よく知られることになった初めての内容かもしれない。
Object Oriented CSS
https://www.slideshare.net/stubbornella/object-oriented-css
とりあえず筆者にとって、まとまったCSS設計との出会いはこれだった。
Nicole Sullivan 氏はプレゼンテーションの中で、自身がどのようにプロジェクトの中でCSSを書き、何をどう改善したのかを発表した。
その中で彼女は言った。「CSS is too fragile」 CSS は壊れやすすぎると。
書いたCSSを壊さないようにするには、積み木をそーっとそーっと積み上げていくのにも似た慎重さが求められると。
このOOCSS以降、CSS設計方法論はいくつも生み出されてきて現在に至るわけなのだが、
これらの考え方は、CSSという積み木をそーっと積み上げるためのやりかたを教えてくれるものである。
ここから先に進む前にまず認識しておかなければならないのは、この「CSSは壊れやすいもの」という視点だ。
先程挙げた例はまさに、何も考えず積み木を積んで、あっという間に壊れてしまいそうなお城を作ったようなものだ。
壊れやすいCSSをどう書いていくかという視点が必要なのだ。
p14
HTMLとCSSを書くという工程の前には、デザインや設計という工程がある。
別にデザイナーに、 CSS のことを1から10まで知っておいてくれとは思わない。
しかし、この本で次回以降書いていくような内容のことを、デザイナーが少しでも知ってくれていたら、コミュニケーションは遥かに楽だったはず。
仕事でHTMLとCSSに関わっていれば、そう思うことはよくある。
だから筆者としては、デザイナーにもある程度CSSのことを理解しておいてほしいと思う。
BEM とは p15
BEMとは以下の3単語の頭文字であり、「ベム」と発音されている。
Block
Element
Modifier
BEM の内容は公式サイトに詳しく解説されている。
この本を読んでなお、詳しく知りたければぜひ参照されたい。
BEM
https://en.bem.info/
BEMとは何か?
一言でいうと「コンポーネントベースでサイトを設計するための方法論」と表現し て間違いないと思う。
コンポーネントって何? p16
コンポーネントとは何か?
普段からプログラムなんかを書いている人でないと、そこまで馴染みのない言葉かもしれない。
このコンポーネントという言葉、直訳すると「構成要素」となる。
しかし「構成要素」などと言われても、そんな曖昧な説明ではわかりっこない。
なのでちょっと例え話をする。
テーブルの上には食べ物がたくさんある。
パンに玉ねぎにアボカドにパセリ、トマト、にんにく、チーズ……。
これらを描くとき、「全部を一気に描くのではなく、一つずつ描いていき、それらを組み合わせる」というのが、コンポーネントと言う考え方に近い。
そのように書いた場合、それぞれの要素のことを「コンポーネント」と呼ぶ。
「チーズ」「にんにく」「トマト」「セロリ」とかいう単位。
この絵を構成している要素がコンポーネントという感じに。
これら一つずつを描いていけば、最終的に絵はできあがる。
構成する要素なので構成要素。
この言葉の意味もなんとなく想像できるだろうか。
ざっくり言うと、これがコンポーネントという考え方である。
ここでミソなのが、こういう、自分でやりやすいように分けた単位を「コンポーネント」って呼んでいるだけというところである。
「コンポーネント」って言葉は正直、みんな適当に使っている。
「モジュール」だとか「部品」だとか「パーツ」とか、色々な呼ばれ方をしている。
Block の定義 p27
Blockの定義。
これは、 BEM の公式サイトではこうある。
「A logically and functionally independent page component」
「論理的/機能的に独立したページコンポーネント」とでも訳すのだろうか。
なるほど?
わかったようなわからないような……。
ここで前回話した「コンポーネント」について思い出してほしい。
「自分でやりやすいように分けた単位を「コンポーネント」って呼んでいるだけというところである」と書いた。
前回は、絵を描くために、「パン」「玉ねぎ」「アボカド」という風に分けて一つずつ描くという話をしたが、
別にこれは、やりやすいように自分で考えたまとまりにすぎない。
自分が描きやすければ「パンと玉ねぎ」「アボカド」という分け方でも別によい。
BEMの話に戻るが、Blockは、ページを構成する部品であるということ。
残念ながらただそれだけだ。
「論理的/機能的に独立した」と言われているが、それもまた曖昧な表現である。
ただ画面をBlockの集まりだと考えて設計すると色々うまくいくぞ。
そういう考え方がBEMなのだ。
つまるところ、ちょうどよい大きさの基準なんてものはない。
それは自分で決めるもので、HTMLとCSSを書く時点で決定しなければならない。
CSS設計の方法論として提供できるのは考え方と実装方法だけで、どう設計するかはあなた次第という感じである。
なるほど? ではどうやってBlockを考えよう p28
どういう風に Block を考えればいいのかには正解がない。
自分が選んだ Block の大きさが、運用されたり他の人が触ったりしたとき、これはいい感じの大きさだねっていう風に評価されるものかもしれない。
ただ、そんな風にノーヒントでは考えようがないので、一応こういう風に決めるヒントがあるかなというのを考えてみた。
ちなみに、コンポーネントがどのくらいの大きさなのかを表現するために、今後「粒度」という言葉を使っていく。
「粒度」と言うのは、構成要素の粗さ、大きさを表現することで、「このBlockは適切な粒度だ」みたいな風に使う。
p29
BEMのまだBの部分しか説明しないので、そんなものなのかなというぐらいの感想しか持てないだろうが、
自分でWebサイトを設計している場合には、どのような粒度でBlockを考えようと、基本的には自由である。
Elementって何? p36
Element を辞書で引くとこういう意味だという。
要素
部分
成分
コンポーネントのときと同様、やっぱりよくわからない……。
BEMの公式サイトでは、Elementの定義は以下であると書かれている。
「A composite part of block that can't be used separately from it」
「ブロックの構成要素であり、切り離して使うことのできないもの」みたいな感じである。
Element については、別にそんなに難しく考える必要はない。
とりあえず、Blockの中にあるあらゆる要素はElementである。
そして、それをどこか別のBlockの中で使ったりするのはNG。
ひとまずこう覚えておくとよい。
p37
これらElementの名前をBlock同様、クラス名に使うわけだが、そのままは使わない。
この文字列の前に、Block名__をつけるのである。
Block名の後ろにアンダースコア2つを続ける。
BEM においては、__はBlock名とElement名を区切るための符号の意味を持つ。
これが Element クラス名の命名ルール。
p39
筆者ならこんなクラス名にすると思う。
見出し: table-set__heading
表: table-set__table
キャプション: table-set__caption
実際にこれらクラス名が指定された要素をどこか別のBlockへ突っ込んでみても、
同じ見栄えが再現されるだろうが、そのような使い方はBEMルールに反する。
この見出しもキャプションも、この table-set 専用というわけだ。
「ブロックの構成要素であり、切り離して使うことのできないもの」が Element なのである。
仮にこの見出しやキャプションを別の場所でも使いたいのであれば、それぞれを単独のBlockとして考えるべきである。
p46
この詳細度の点数について、何が強くてどうすれば勝てるみたいなルールを細かく覚えておく必要はほとんどないと筆者は考えている。
興味があれば調べてみるとよいと思うが、正直、筆者は詳しく覚えていない。
筆者が覚えているのは、
1. id セレクタ
2. クラスセレクタ
3. 要素セレクタ
の順で強いと言うくらいだ。
読者のみなさんも、これを覚えておくくらいでいいんじゃないかと思う。
こんな風に、詳細度の勝ち負けみたいな状況を起こさないようにするのが重要なところなのである。
BEMはこの心配を非常に少ないものにしてくれる。
Element in Element はナシ p47
よくある勘違いなのでここで軽く触れておくが、以下のようなクラス名はBEM的にはナシである。
先程のカードUIのHTMLのバリエーションだ。
<div class="card">
<img class="card__img" alt="..." src="..." />
<div class="card__body">
<h5 class="card__body_title"> Product title</h5>
<p class="card__body__text">The quick brown fox jumps...</p>
<a class="card__body__btn" href="#">Buy</a>
</div>
</div>
何がナシかというと、card__body__titleのように、__がクラス名に2回入っているところである。
bodyの配下にtitle、text、btnがあるので、Elementの構造を__で表すと上記のようになりそうだが、
BEMとしてはElementの構造をクラス名の中で表現するルールはない。
筆者としては、このようなルールがないのは、BEM的には、Block名とElement名という単純な2階層構造で考えよという思想なのであろうと捉えている。
このルールを許容するとすると、どんなに深い階層でも表現できるわけだが、その分Blockの粒度が大きくなってしまう。
粒度の大きすぎるBlockは本当にその粒度で最適かどうかを疑ったほうがよい。
この階層化を多用したくなってきたときは、粒度が大きすぎるぞという警告だと、理解しておいてよいのではないかと筆者は考える。
ちょっとだけこういうことをしたいくらいであれば、card__body-titleなどとして済ますのをおすすめする。
Modifierって何? p47
modify とは 「変える」という意味。
つまり、 Modifier とは「変えるヤツ」。
何を変えるのかと言うと、BlockやElementを変えるのである。
Modifier は、 Block や Element のバリエーションを作ったり、状態を表現したりするときに使う。
アッパーキャメルケースが好き p55
筆者個人としては、Block名とElement名はアッパーキャメルケースで書いておくのが好みである。
以下のように。
.GlobalPrimaryNav__MenuItem--active { ... }
これには一応理由がある。
別にこの方法に準じるべきであるとかは思わないが、コラム的にちょっと自分の考えを紹介しておく。
Block や Element というのは、何かしらのUIをHTMLとCSSで表現するために考え出された、抽象的な概念である。
その抽象的な概念を、コードに落とし込む際に、HTMLとCSSでクラス名を介してスタイルを当てているわけである。
言ってみれば、 Block や Element は、具体的に画面にレンダリングされる UI の雛形と言えなくもない。
Ruby なり Java なり、なんでもいいのだが、多くのプログラミング言語では、雛形的な存在である「クラス」は、大文字で始めるのが一般的な命名規則になっている。
そのようなプログラミング言語的な慣習に倣えば、 Block や Element を示す言葉というのは、
大文字で始めたほうが違和感がないのではないか?などと考えているが、まあ単に個人の考えでしかないので、読者のみなさんは好きに書けばいいと筆者は思う。
p57
ただそれだとHTMLがクラスだらけになってしまう。
こんな単純なHTMLなのに。
面倒なのでクラスをつけるのをサボりたい……。
そんなときにはこう書きたくなるだろう。
.header-nav__item a {
display:block;
padding: 1em .3em;
}
おいおい BEM 的にはクラスセレクタで全部やるんだろう?と心の中で怒られる感じがするかもしれないが、
実はBEMとしてはこのように書いても別によいというスタンスをとっている。
これだったらだいぶHTMLがごちゃごちゃせずにスッキリする。
しかし、これまでにも何度か書いてきたが、このように、クラスセレクタ以外のセレクタを多用すると、ルールの詳細度に差が出てきてしまう。
前述したとおり、詳細度の差によりどっちのスタイルがあたるのか?みたいな状況は、絶対に発生させたくない。
なので、BEMとしては、こういう書き方は禁止はしないが、ご利用は計画的にということのようである。
筆者としては、今例に挙げたようなケースであれば、積極的にクラス名を付けるのをサボる。
なぜなら、この場合は、 li 要素の配下には、 a 要素以外が入る見込みがほぼないためである。
ここに色々な要素が入ってくるとすると、こんな風に子孫セレクタを使ったら、意図しない描画結果になることがあるかもしれない。
しかし、ごく限られたスコープで、限られた要素しか入り得ないのであれば、長ったらしいクラス名を付けるのをサボったほうが、HTMLの見通しはよくなることが多いと思う。
あとで自分や他人が見たときに混乱しない程度に、このような書き方をしていくのがよいと筆者は考える。
Blockという単語についての補足 p58
これまで何度も「コンポーネント」という言葉を使ってきたが、 BEM では、そのコンポーネントの呼び名として「Block」という言葉を使っている。
BEMを始めとする各種CSS設計方法論において、「コンポーネント」という言葉が示すものは、管理上都合のよい大きさのUIのまとまりと言える。
この「コンポーネント」というもの、CSS設計方法論、JavaScriptのフレームワーク、デザインシステムなどで、さまざまな呼ばれ方をする。
「モジュール」だったり「オブジェクト」だったりというように。
最近では「コンポーネント」と呼ばれることが多い印象だが、とりあえず本書ではBEMベースで話を進めていくので、
このUIのまとまりのことを、引き続き「Block」と呼んでいくことにする。
SMACSS p59
この4つのトピックのうち、はじめの3つは、SMACSSという考え方を元にしている。
SMACSS というのは Scalable and Modular Architecture for CSS の略で、「スマックス」と読む。
著者はWebデザイナー/デベロッパーであるJonathan Snook氏で、当時Yahoo!に勤めながら得た知識を元に書いたとのこと。
この書籍は2012年に発売され、今となってはクラシックな内容となったが、
この本はとてもシンプルにまとまっており、設計の理解のためには今でも有益であると筆者は考える。
そんなに長い本ではないので、本書を読んで気になった方は原著を読んでみることをオススメする。
SMACSSはWebサイトで全文が公開されており、日本語に訳されたものもある。
SMACSS
http://smacss.com
SMACSS: 日本語訳
http://smacss.com/ja
normalize.css のアプローチ p63
3箇所ほど例を挙げたが、こんなコードの集まりが normalize.css 。
normalize.css を一言で表すと、「なんか色々いい感じにならしてくれるCSSルールのセット」である。
よし、ブラウザのデフォルトスタイルを活かしてCSSを書くぞ!と思ったら、
ここで挙げたようなブラウザごとの差異を知らなければ、どこかでつまずくかもしれない。
とは言え、こういった事情をすべて把握しておくのはだいぶ辛いだろう。
section 内で h1 の font-size と margin がブラウザによって異なってしまうこと、
Firefoxでfieldsetの padding が異なってしまうことは、知識として覚えておかなければならないことだろうか。
筆者はそうは思わない。
そんなバグのような挙動を筆者は全く覚えていない。
こういう面倒な調整は、 normalize.css に任せてしまうのがよい。
normalize.css が勝手にいい感じにスタイルの差を埋めてくれるわけだ。
そんな風に、ブラウザのデフォルトスタイルの差異を吸収するのが normalize.css のアプローチである。
とりあえず初めに normalize.css を読み込ませることで、ブラウザごとのバグとも言えるような差異について、考えなくてよい状態にすることができる便利なヤツである。
Base ルールを設計しよう p67
こんな normalize.css と Reset CSS であるが、この2つのうちのいずれかをBaseルールの土台として選ぶと、以降のCSS設計が楽になる。
と言うより、実務的にガリガリHTMLとCSSを書いている人は皆、このようなCSSのルールセットをどこから探してきて、CSS設計時に使っていると思っておいて間違いない。
このような、ベースのベースみたいなCSSファイルを読み込ませ、それに加えて自身で土台としたいCSSのルールをいくつか追加し、 Base ルールとするのがオススメの方法である。
p68
Block を作るたびに同じ文字関連のスタイルを当てるのは手間だし、無駄が多い。
日本語のWebサイトでは斜体が使われることはほぼないので、emはただのboldに、取り立て強い強調の strong は 常に赤に……
という具合に、要素レベルで当てるスタイルがある程度決まっているのであれば、こんな風にBaseルールとしてスタイルを当ててしまう。
そんな風にしてWebサイトの土台となるルール群をまとめたものをbase.cssなどというファイル名で保存し、
reset.cssかnormalize.cssの後にこれを最初に読み込ませれば、Baseルールの完成。
以降、効率的にBlockを書いていける。
Layout ルールのコード例 p72
このLayoutルール、何ら難しいことはない。
今例で挙げたような、レイアウトのためのルールをただ「Layoutルール」と呼ぼうというだけである。
言ってみれば、 Block を突っ込む箱のためのCSSがLayoutルールである。
よし画面のHTMLとCSSを書いていこう!となったら、Blockのコードを書くその前に、
これらの枠組み部分をまずは作り、その中にBlockを詰めていくという流れで考えるとやりやすい。
この枠部分、コードとしては例えば以下のようになる。
<header class="layout-header-area">
Header
</header>
<div class="layout-body-area">
<div class="layout-side-area-a">
Side A
</div>
<main class="layout-main-area">
Main
</main>
<div class="layout-side-area-b">
Side B
</div>
</div>
<footer class="layout-footer">
Footer
</footer>
これらの要素を、flexboxなりgrid layoutなりで自由にレイアウトすればいい。
別にどうスタイルを当てろというのは決まっているわけではない。
とりあえず、クラスを割り当てて、クラスセレクタでスタイルを当てていくのがシンプルだろうと筆者は考える。
.layout-header-area { ... }
.layout-body-area { ... }
.layout-side-area-a { ... }
.layout-main-area { ... }
.layout-side-area-b { ... }
.layout-footer-area { ... }
こんな風に枠部分を作ってから、中に詰めていく内容であるBlockを書いていくという流れでコードを書く。
これがSMACSSが「Layout ルール」として分類しているCSSのルールである。
Layout ルールは基本的にはこれだけ。
自分もそういう風に書いてますよ。と感じられる方は多いのじゃないだろうか。
後は補足的な内容を書いていく。
idセレクタを使うべきか p73
ちょっと昔話っぽくなるが、このレイアウトのために配置した要素群、昔はid属性を付け、idセレクタを使ってスタイルを当てていくことが多かった。
SMACSSの内容にも、「昔からレイアウトのための要素にはid属性が使われてきた」という旨の記述があるし、SMACSSに掲載されているサンプルコードも、レイアウト目的にidセレクタを使用している。
筆者自身もHTMLとCSSをずっと仕事で書いてきたが、2010年頃はみんなidセレクタでレイアウトを書いていたように思う。
p74
このように全体のレイアウトを定義するときにidを使っていたのは、以下のような理由があったからのように思う。
それぞれのエリアが2度以上登場することはほぼないから
全体用レイアウトはidで定義することで他のCSSルールと分類する
大枠のエリアは、ページ内のアンカーリンク先として使用することも多い
JavaScriptのフックとして利用することもまあまあある
これらは、言われてみると確かにそうかもと思えるかもしれないが、
一つずつ吟味してみれば、レイアウトのためにidセレクタを利用すべきであるという強い理由付けにはならない。
筆者としては、idセレクタを使うことで発生するデメリットも存在するので、
単純にクラスセレクタでスタイルを当てたほうがよいだろうと考えている。
その理由は以下のようなことが挙げられる。
idはJavaScriptのために使用したい (特定の要素を識別するのにid属性は便利)
セレクタの詳細度が強くなってしまう (idセレクタの方がクラスセレクタよりも強い)
全体のレイアウト枠組みのような要素でも、タイミング的に2つ以上出現してしまうことがある
メインエリアのような枠組みの要素が2つ登場したりするのか?そんなことあり得ないだろうと思われるかもしれない。
しかし、例えば画面全体がフェードアウトし、次の画面がフェードインしてくるみたいなインタラクションを実装する場合、
わずかな時間であるが、同じidの要素が2つ画面に登場してしまうということはあり得る。
そんなことは滅多にないというのはそうなのだが、そうなった場合に書いたJavaScriptが動かない可能性はゼロではなく、
その場合に不具合の原因を見つけるのは困難であることが予想される。
そういう状況に遭遇してしまうのは、端的に言って辛い。
詳細度の差が発生する問題も、ここまで本書を読んでくださっている読者のみなさんは理解できるであろうと思う。
クラスセレクタを使ってレイアウトを組んでも何かしら目立ったデメリットはないことを考えると、
わざわざトラブルの発生しそうなidをここに使う必要はないだろうというのが筆者の意見である。
BEMっぽくレイアウトを定義する p75
idセレクタを使わないのであればどう書くのか?
筆者としては全体のレイアウトを一つのBlockとして、BEM的に考えるのをオススメしたい。
先程の例だと例えば以下のような形にする。
<header class="global-layout__header-area">
...
</header>
<div class="global-layout__body-area">
<div class="global-layout__side-area-a">
...
</div>
<main class="global-layout__main-area">
...
</main>
<div class="global-layout__side-area-b">
...
</div>
</div>
<footer class="global-layout__footer">
...
</footer>
global-layout という名前のBlockが画面全体を表現し、各エリアを element という扱いにするという具合である。
これであれば、例えばメインエリアの以下のdivを目にしたとき、これは全体のレイアウトの一部なんだということがひと目でわかる。
<main class="global-layout_main-area">
...
</main>
SMACSS的には、レイアウト用のセレクタをどうせよという決まりのようなものはなく、
設計のアイデアを紹介しているだけなので、このあたりは自分の好きなように書くとよいと思うが、
BEMを採用してコードを書いているのであれば、このように書いてみると、他のコードとの親和性が高まるかもしれない。
p83
CSSの便利さをプレゼンするにはいいネタだろうが、実務でこういうことをするケースはそんなにないんじゃないだろうか。
少なくとも筆者にとっては、10年以上Web業界にいて、1度か2度、やったことがあったようななかったような……というぐらいの頻度である。
ただこの「Themeルール」、テーマ機能を実装するという考え方ではなく、
html要素のようなルートの、言ってみればグローバルなところで切り替えのためのキーを用意し、
それに応じてスタイルを分岐させるという視点で考えると、様々に応用が可能だったりする。
!important p95
このようなユーティリティクラスは、同じ詳細度のルールは、
最後に読み込まれたものが勝つという仕様があるため、読み込ませる CSS の最後に書いたりされる。
完全に純粋なBEMで書かれていれば、基本的にすべてのCSSルールは単独のクラスセレクタになっているであろうから、
後に書いたセレクタが勝つだろうが、詳細度でユーティリティクラスのスタイルが負けてしまう場合、以下のように !important をつけてスタイルを宣言したりしてもよいのではないかと筆者は考える。
.align-left { text-align:left !important; }
.align-center { text-align: center !important; }
.align-right { text-align:right !important; }
ユーティリティクラスは部分的にスタイルを変えるために使うので、
ユーティリティクラスで指定したスタイルを、さらに上書きするようなことは基本的に想定されない。
なので、 !important を使うことでなにか問題が発生する可能性は低いハズである。
p96
こんなBEMにとっては、このユーティリティクラスという存在、コンポーネント化のルールをぶち壊してしまう存在であることを、まずは念頭に置いてほしい。
BEM的な設計を基本とするのであれば、ユーティリティクラスはあくまで例外的な処理であり、
何でもかんでもユーティリティクラスでやろうとすれば、 BEM で設計している意味はどんどん薄れていくのである。
p100
クラス名の頭にはすべて cssmania- を付けるのだ。
こうしておけば、 alert というクラスに何かしらスタイルが当てられていても衝突は起こらない。
普通に考えて、見ず知らずの他人が cssmania- という文字列をクラス名の頭につけている可能性はほぼゼロであろう。
この cssmania- という、クラス名の頭につけている文字列を、本書では「名前空間的接頭辞」と呼ぶことにする。
この「名前空間的接頭辞」という言葉、世間一般で広く使われている言葉ではなく、筆者がこの原稿を書きながら考えた言葉というだけである。
3. ルールのカテゴライズを示す文字列 p106
3つ目は、2つ目の延長ではあるが、BEMで設計された部分以外のクラス名にも、そのクラスのカテゴライズを示す接頭辞をつけようというものである。
BEMのクラスへ付けるのは b- だ。
であれば、 Theme ルールなら theme- や t- 、 Layout ルールなら layout- や l- 、
ユーティリティクラスなら util- や u- という接頭辞を用意してみる。
余白の問題というのはどういうことか p111
余白余白と、何のことを言っているのかと感じている読者の方は多いと思うので、
まずは、どういう困ったことが発生するのかを、ごく単純な例で紹介する。
ここで言う余白は、主に縦方向、取り立てて Block 間の余白についてである。
横方向の余白についてはここから先で解説するような話は関係してこないので、切り分けて考えると理解しやすいのではないかと筆者は考える。
横の余白と縦の余白は別物として考える。
あくまで筆者の考えではあるが、たぶん実装としてはそういう認識でいる方が色々と都合がよいと思う。
p117
その余白設計の考え方の一つとして、余白のバリエーションをあらかじめ決定するという方法がある。
まずは何パターンかの余白を用意し、新しくBlockを配置する際、その上下の余白は、このバリエーションの中から選ぶのだ。
このとき、既存の余白バリエーションでは足りないと感じたら、新しい意味合いを持つ余白のバリエーションを追加するという具合だ。
p131
このBlockの一番外側の要素について、上にも下にもmarginが設定されていないのであれば、
上記のように3つ並べると、その3つのBlockはピッタリくっつく。
これがBlockに余白がまだ設定されていない状態。
今回書くのは、このBlockについて、どう言う風にCSSで余白を設定するかという話である。
この余白の設定方法について、以下3パターンのいずれかで考えるとわかりやすいと筆者は考える。
1. Block自体に余白を設定する
2. 余白専用Blockを作る
3. 余白用ユーティリティクラスを使う
実装方法3: 余白用のユーティリティクラスを用意する p135
3つめの方法は、余白用のユーティリティクラスを用意するという方法である。
これは、2つめの方法である余白専用Blockの役割を、ユーティリティクラスに担わせただけである。
一つ前の方法のように、Block自体にはmargin-bottomをつけず、以下のようなユーティリティクラスを用意する。
.block-name {
``` ここでは下にmarginを付けない ```
}
``` 狭めの余白 * /
.util-block-spacing-s {
margin-bottom: 15px;
}
``` 基本の余白 * /
.util-block-spacing-m {
margin-bottom: 30px;
}
``` 広めの余白 ```
.util-block-spacing-l {
margin-bottom: 50px;
}
そして以下のように、 Block に対してこれらのユーティリティクラスを使うという具合になる。
<!-- 狭めの余白 -->
<div class="block-name util-block-spacing-s">...</div>
<!-- 基本の余白 -->
<div class="block-name util-block-spacing-m">...</div>
<!-- 広めの余白 -->
<div class="block-name util-block-spacing-l">...</div>
この方法のメリットとデメリットは、一つ前の余白専用 Block とほぼ同じ。
余白をつけるためにdivを増やすか、クラスを足すかという違いである。
毎度毎度クラスを足さなければならないが、多様に余白を変化させることができる。
余白専用Blockと比較すると、divの数が減るので、HTML的にはシンプルと言えるかもしれない。
その代わりにclassが少しゴチャっとする。
ユーティリティクラスというものの存在は、
BEMルール的には、どこへでも変化をもたらすことのできる使いすぎ要注意な存在なので、
そのあたりはCSS設計に複雑さをもたらしているとも言える。
margin の相殺は使わない p136
これは一つの設計のポリシーであり、必ずそうするべきとは思わないが、marginの相殺には頼らないほうがよいと筆者は考えている。
marginの相殺とは、以下のようなことを言う。
<div class="block-example-a">...</div>
<div class="block-example-b">...</div>
.block-example-a {
margin-bottom: 30px;
``` 下に30px ```
}
.block-example-b {
margin-top: 50px;
``` 上に50px ```
}
このとき、この2つのBlockの間には何ピクセルの余白が取られるかと言うと、30 + 50 の 80pxではなく、50pxになるというもの。
こんな風に縦方向のmarginが被る部分は相殺されるというのは、CSSの仕様である。
この相殺は、入れ子になった要素に指定された縦方向のmarginについても同様に機能する。
これをうまく活かせば、Blockの上下にmarginを指定しても柔軟な余白設計ができるように感じられるかもしれないが、現実的にはなかなか難しい。
なぜかと言うと、marginと共に float に left や right が指定されていたり、
display が flex である要素をまたいだりすると、このmarginの相殺は発生しなくなるためである。
大体の要素の下余白をmargin-bottomで取っていたとしても、こういうケースが一例でもあると、そこではmarginの相殺に頼れなくなってしまう。
そんなこんなで、端的に言うとmargin相殺はややこしい。
なので筆者はこれに頼りたくない。
こういった余白設計の際、下方向の余白を margin で確保するのであれば、上方向の余白はあえて padding にし、相殺を起こさないようにしたりすることをオススメしておく。
HTMLとCSSを書く人に求められることの難しさ p147
この「別の工程と一緒になって自分の実装をする」というのが、
HTMLとCSSを書くことの難しさのうちの一つであることは間違いないと筆者は考える。
とくに、デザイナーと一緒になって作っていかなければならない。
デザイナーにはデザイナーの考えがある。
実装者には実装者の考えがある。
この2つは必ずしも合致するわけではない。
しかし、どう考えが違おうとも、最終的に完成するコードはひとつ、HTMLとCSSに落とし込まなければWebページは完成しないのだ。
だったらどうするかと言えば、デザイナーは実装者の考えを、実装者はデザイナーの考えを汲み取らなければならない。
デザイナー作っているものは、あくまで中間成果物。
それを印刷して配布したりすることもない。
ただHTMLとCSSを書くという次のステップに引き渡し、それが完了したらもう用が済むものなのである。
なので、デザイナーにはキャンバスに自由に絵を書いている気持ちでいてもらっては困る。
HTMLとCSSの制約を理解し、運用を考慮し、実装する際に無理のないデザインのルールを敷いてもらわなければならない。
そして実装者は、ただ絵をHTMLとCSSに変換するような気分でいてもらっては困る。
デザインカンプは、実装者が実装をするためだけに作られている。
実装者には、この余白はなぜ30pxなのか、どうして似た色があるのに別の色にしているのか、気にかけなければならないし、
なんならこのステップでデザインを完成させるためのレビュアーの役も担っているぐらいの気持ちでいてほしい。
HTMLとCSSを書くということは、実際にコードを書くのは実装者のあなたただ一人かもしれないが、一人で完結するものではない。
このことについて理解し、コミュニケーションを取りながらコードを完成させること。これが難しい。
なので、CSSを書く人が集まって話す内容というのは、ピュアに技術だけの話にならなかったりする。
プロジェクトの背景だったり、デザイナーとの関わりだったり、そういう話で盛り上がったりする。
それはごく自然なことで、そういう、実際にコードを書く以外の要素が、
HTMLとCSSを書くという仕事の中で重要な要素だったりするからなのである。
Atomic Design p148
Atomic Design という書籍がある。
これは Brad Frost 氏の著書で、デザインシステムを中心とした設計の方法について書かれている。
Atomic Design
https://atomicdesign.bradfrost.com/
コンポーネントの粒度やUIの考え方として参考になる部分が多く、興味があれば是非読んでみることをおすすめしたいが、
この本の中で、プロジェクトの進め方について語られている部分があるので、それを紹介したい。
Atomic Design の中では、「Death to waterfall」という見出しで書かれている内容である。
「Death to waterfall」とは「ウォーターフォールに死を」という意味である。
ウォーターフォールとは p148
ウォーターフォールとは、開発の進め方に付けられた名前で、「ウォーターフォール型開発」のことを指す。
「ウォーターフォール」の意味は「滝」。
それぞれの工程が分けられ、一つの工程が完了したら次の工程を行うような形で進める開発のやり方のことを指す。
Atomic Design では、以下のような図を使ってウォーターフォール型開発を表現している。
例えば車を作るとしたら、まずネジを作るし、ネジを作らなければエンジンは作れず、エンジンを作らなければ車は完成しない。
なので、まずはネジを作る。
そしてネジを作り終わったら、次にエンジンを作る。
そしてエンジンを作り終わったら、最後に他の部品と組み合わせて車を完成させる。
当たり前のことであり、それで何もおかしいことはないように思われるが、
Atomic Design 曰く、このようなウォーターフォール型開発でWebサイトを作るのはダメだということである。
スタイルガイドとはこういうもの p153
まず、スタイルガイドとはなんだろうか。
スタイルガイドという言葉が示すものの幅はなかなかに広いが、端的に言うと、デザインやコードの記述方法などについてまとめた資料のこと。
このスタイルガイド、企業やWebサービスが、自社で作っているものを公開していたりする。
とりあえず具体例を見てもらったほうがわかりやすいと思うので、以下の3つについて、軽く紹介してみる。
1. Google HTML/CSS Style Guide
2. Dropbox (S) CSS Style Guide
3. Primer
ただのテキストファイルでよい p158
このコーディングルール、別に立派なドキュメントである必要ではなく、
コーディングしたときに決めたルールが箇条書きになっているものがテキストファイルになっているだけでも十分有用である。
紹介したDropboxのスタイルガイドは、ただのMarkdownファイルである。
筆者もこういったテキストはよく作るが、大体 Markdown ファイルで書いている。
プロジェクトのディレクトリに、README.mdだったりREADME.txtといった名前でこれを置いておけばよい。
このファイルには、以下のような内容が書かれていると大変有意義である。
CSS設計の方法 (BEMを基本とするなど)
クラス名の命名規則 (MyBlockName なのか my-block-name なのか)
画像やSVG ファイルの置き場所
JavaScriptファイルの置き場所
ビルドの方法やツール
ファイル、ディレクトリ名の命名規則
余白設計のルール
どういった内容をここに含めるべきかは、是非 Google や Dropbox のスタイルガイドを参考にしてほしい。
こういった情報がまとまっているだけで、チームメンバーを大きく助けることができる。
超単純コンポーネント一覧 p159
次にスタイルガイドにまとめたいのは、コンポーネントの一覧。
GitHub の Primerで紹介したようなものである。
ここでいうコンポーネントとはBEMでいうBlockのこと。
作ったBlockを列挙しておくと、色々とよいことがある。
Primerでは、一つ一つのコンポーネントに対して事細かに説明が書かれているが、
そんなに丁寧にまとめあげなくとも、ひとまず単純に作ったBlockのコードを並べたHTMLを作っておくだけで開発の大きな助けになる。
この画面に、プロジェクト内で作ったBlockを同じようにひたすら並べていく。
すると、このページを見ただけで、どういうBlockがそのプロジェクト内で用意されているのかが一覧できる。
Blockの数が多くなるようであれば、HTMLを分けるとよりわかりやすい。
例えば製品情報で使うBlockは、products.htmlにまとめておくとか、トップページで使うBlockはtop.htmlにまとめておくなどである。
そうすれば、画面ごとにその画面で使えるコンポーネントがどれなのかをすぐに判断することができる。
仕組みとして何か難しいことは全くない。
ただこれだけである。
コンポーネント一覧の何がありがたいか p161
このコンポーネントの一覧、これがあることで何が嬉しいのか。
例えば、製品情報の画面を作った後に、会社情報の画面を作るという流れでHTMLとCSSを書いていたとする。
会社情報のHTMLとCSSを書いていく中で、デザインカンプにあるUIをBlockに分けてコツコツコーディングしていくわけであるが、
ふと、「あれ?このBlockって、製品情報でも作った気がするぞ……?」ということに気づく。
よし、では製品情報の画面を見直してみようと思い、製品情報のHTMLを確認してみるも、
製品情報はもうすでにECのパッケージに組み込まれた後の状態だった。
ECのパッケージに組み込まれた HTML は、すでにPHPが混ざり、条件により書き出されるHTMLが分岐する処理がすでに入っている状態となっていた。
ECパッケージの組み込みはまだ途中の段階で、ローカル環境で動かすことはまだ難しい状況であった。
ここからすでに作ったHTMLを抜き出してくるのは若干労力がかかる。
……こんなとき、ただBlockを並べただけでもいいので、コンポーネント一覧を作っておいたらどうだろう。
そこからコピペしてくるだけでよかったはず。
そもそも、「製品情報で作った気がするぞ……?」ということに気づくことができなければ、
2度、同じUIをコーディングしてしまうことになるだろう。
自分で両方の画面を作っているなら気づくだろうが、
開発が引き継がれたみたいな状況では、どういうBlockがコーディングされているのかを把握するのはもっと難しい。
BlockのHTMLを列挙したHTMLが一枚あるだけで、こういった問題に陥らなくて済むようになる。
これは非常に大きい。
コンポーネント一覧を前提としたコーディングの流れ p162
なるほどコンポーネントの一覧はありがたい。
でもこれって、Block作った後に逐一コピペして作るんですか?と思われるかもしれない。
別にそれでもよいのだが、筆者的にはむしろ、コンポーネント一覧のHTML上でBlockのHTMLを書きながら、
完成したHTMLのコードを具体的な画面へとコピぺし、最終的なテキストや画像素材を入れるという流れで作業を行うのをオススメする。
雛形を先に作って効率アップ p163
なぜそうするのかと言うと、そのような流れで実装を行うと、CSSを書くときは具体的なテキストや画像素材について気にしなくてよくなるというのが1つ目の理由。
この結果、 実装効率が上がるかもしれない。
実際に公開する画面のHTMLへは、当然ながら、その画面で読ませたいテキストや、見せたい画像を入れる必要がある。
しかし、CSSを書くためには、テキストや画像はなんでもよく、ダミーのテキストや画像が入っているだけで十分である。
HTMLの文法とCSSについて考えながらコードを書かなければならないところに加え、
「この原稿や画像は正しいのか?」「誤字脱字がないか?」みたいなことにも気を回していては、気が散ってしまう。
まずはコンポーネント一覧のHTMLにて、 Block の雛形を作る。
それを集中して終わらせた後に、本場の原稿や画像を入れるという流れで作業をすすめるのが楽である。
長くテキストを入れた場合にどうなるか、画像のサイズがもっと大きくなったらどうなるか……などの検証も、
雛形を作り、原稿を流し込むという流れで作業したほうがやりやすい。
コンポーネント一覧の更新漏れを防ぐ p163
2つめの理由は、具体的な画面を作った後にコンポーネント一覧を更新しようとすると、
コンポーネント一覧を最新の状態に保てなくなる可能性が発生するからである。
例えば、一日の終わり間際、終業ギリギリでBlockのHTMLとCSSを作り終え、明日コンポーネント一覧を更新しようなどと思い帰路につく。
次の日、突然急ぎの仕事が入ってきたら、コンポーネント一覧は更新されないまま終わるのではなかろうか。
それは実装者個人の問題でしょうと思われるかもしれないが、コンポーネント一覧で新しいBlockを作り、
具体的な画面のHTMLを書くときは、コンポーネント一覧からHTMLをコピペする。
この流れを厳守するだけで、このような漏れが発生する可能性はゼロになる。
いきなり具体的な画面でHTMLとCSSを書いている人にとっては、若干面倒に感じられるかもしれないが、
この流れでコードを書いていくことで、コンポーネント一覧は自動的に完成する。
これにより得られる恩恵は大きい。
コンポーネント一覧のメンテナンス p164
一通り開発が完了し、運用のフェーズになると、コンポーネント一覧は放置されてしまいがちになるかもしれない。
というのは、運用のフェーズになると、一からHTMLとCSSを書いているわけではないので、動いているコードに手を付けたほうが早いためである。
今例として挙げたような、書いたHTMLをECパッケージに組み込むみたいなケースを想像してみてほしい。
公開後、アイコンの位置がズレていたことに気づき、すでにPHPに組み込まれたHTMLの断片をちょっといじって修正を完了させた。
こういうことは、よくあることかと思う。
しかし、このような場合でも、可能ならコンポーネント一覧を更新するところから始める方がよい。
そうしないと、コンポーネント一覧のHTMLには、修正前の壊れた状態のコードが混ざってしまうことになる。
このように更新されなくなったコンポーネント一覧は、そこにあるものが最新のコードなのか否かが判断できなくなった時点で、全く意味のないものとなってしまうのだ。
後からコンポーネント一覧を整備するというのは大変な作業になることがある。
なぜなら、そこに列挙されているコードがそれぞれ最新の状態かを確かめる手軽な方法は存在しないため、一つ一つ確認し直さなければならない。
コンポーネント一覧を直すことから始めれば、このコストは最小限になるので、
そんな風に壊れたコンポーネント一覧を直して回るのは、まったくもって無駄な作業コストである。
個人のサイトやブログなど、小規模なWebサイトであれば、コンポーネント一覧をメンテナンスし続ける必要性は薄いと思うが、
長く運用されるWebアプリケーションや企業のWebサイトなどでは、コンポーネント一覧の存在が、運用にかかる工数に影響してくるだろう。
どこまでスタイルガイドを作り込むべきか p167
こんな風に、スタイルガイド作成を補助してくれるソフトウェアを導入することで、比較的手軽に利便性の高いスタイルガイドを作り上げることができる。
hologram 、 Storybook と紹介したが、筆者としては、
このようにスタイルガイドを作るためのソフトウェアとしては、 Storybook 一強という印象である。
SCSS syntax か Sass syntax p190
ここまででSassのコードとして挙げている例はすべて、 SCSS syntax (SCSS構文) で書いたものである。
実は Sass にはもう一つ、 Sass syntax (Sass構文) というものがある。
今回、初めに挙げた例を Sass syntax で書き直すと、以下のようになる。
section P
> h2
font-size: 2em
padding: 0 0 20px
p
padding: 0 0 30px
ul
padding: 0 0 20px
> li
padding: 0 0 10px
.pageType-top
border: 1px solid black
Sass syntaxでは、 { } は使わない。
その代わりに1段階インデントを入れるのである。
どちらを使ってもよいのだが、 SCSS syntax の方が圧倒的に多く使われている印象だ。
{ } の代わりにインデントを入れるというのは、それはそれで楽なのだが、筆者は仕事で Sass syntax を採用しているプロジェクトに出会ったことがない。
端的に言って Sass syntax はマイナーである。
第 20 回 ビルドしてCSSを作る: Autoprefixer p197
今回は Autoprefixer を紹介する。
Autoprefixer
https://github.com/postcss/autoprefixer
Autoprefixer は、CSS設計と大して関係ないが、この存在を知らないと、
ブラウザの対応がイマイチなプロパティについて悩むこと請け合いなので、ビルドの解説の一環として本書の内容に含めることにした。
開発に組み込むべきかは状況により判断すればよいと思うが、今回紹介する内容は、知識としてはほとんど必須と言っていい。
また、次回紹介する PostCSS の理解のためにも適した題材である。
PostCSSとは p204
PostCSS は、CSSに対して何かしらの変換処理を行い、別のCSSを出力するAPIを提供するソフトウェアである。
これまで紹介してきたものと同様、 npm のパッケージとして配布されている。
PostCSS
https://postcss.org/
Sassについて紹介した際、SassはCSSのプリプロセッサと呼ばれることがあると書いたが、
PostCSSはその逆、 CSSのポストプロセッサと呼ばれる。
「CSSを変換して別のCSSを出力……? 何を言っているんだ?」と思われるかもしれないが、
一つ前に紹介した Autoprefixer はまさにこれを行っていた。
cssnano p206
cssnano
https://cssnano.co/
cssnano は、 CSS を minify してくれるプラグインである。
本書ではすでに minify として clean-css-cli というものを紹介したが、似たようなものである。
重複する宣言を省いてくれたり、ショートハンドにできるところは勝手にショートハンドにしたりもしてくれるらしい。
p220
しかし、 Enduring CSS という書籍を読み、まるっきり考え方が逆になった。
この書籍は、 Ben Frain 氏が、 CSS 設計が破綻しないように運用していくにはどうすればよいのかについて書いたものである。
Enduring CSS
https://ecss.benfrain.com/
enduring を辞書で引くと、「長期間続く」「永続的な」「辛抱強い」という訳が並んでいる。
この本では、ここまでに書いた、 Block (ECSS では Module と呼んでいる) を汎用的に設計することにより起こるデメリットを回避することが重要だと説き、なるべく限定的にBlockを設計するよう勧めている。
汎用的なBlockをたくさん作ってしまうと、どんどんCSSを触るのが難しくなってしまい、いずれ破綻するというような内容が書かれている。
これは、前述した「汎用性な名前にしたときのデメリット」で解説した内容である。
名前空間的接頭辞 p221
ECSS では、Blockの頭に、名前空間を示す文字列を付与することをルールとしている。
さっきから例に出している faq-contact-block の faq- がまさにそれである。
本書では、第12回で「名前空間的接頭辞」とこれを呼んだが、これを絶対に付けるようにし、この接頭辞により、そのBlockの分類を示すようにせよということだ。
例えばこの接頭辞を、 Web サイトの構造上の分類を示すものにしたとする。
そして、 faq- であれば、 FAQ カテゴリの中でしか使わないというようなルールにする。
こうすることで、 Block のクラス名を見ただけで、そのBlockがどこまでの限定さを持ったものなのかを判断できる。
製品情報であれば products- 、 トップページであれば top- 。
こういう風に書かれたHTMLとCSSを見ると、「ああ、今トップページを編集しているが、このtop-contact-blockをいじっても他の画面でレイアウトが崩れることはないな」と安心できるわけだ。
コードが重複してもよいのか p221
しかしながら、このように限定的に使用する用途で設計された Block には、先程から挙げているようにデメリットもある。
この問題について、 ECSS ではどう考えるのかを紹介しておく。
まずコードの重複について。
FAQ用お問い合わせのブロックをfaq-contact-block、製品情報用にはproducts-contact-block、トップ用にはtop-contact-blockとしたとして、それが同じ見栄えだったらどうする?
同じCSSをコピペしたらいいのか?そんなことをしたら、同じCSSのコードが何度も登場することになってしまう。
この問題に対するECSSの答えはなんと「コピペしとけ」である。
Sass を使っているのであれば、 mixin なんかで共通のスタイルをまとめ、抽象化することは可能である。
しかし、ECSSではそれも推奨しない。
同じ見栄えでも、名前空間が別ならば別物として扱えというのだ。
つまり、FAQ用に作ったfaq-contact-blockと、製品情報用に作ったproducts-contact-blockが、全く同じ見栄えをしていて、そのCSSもほぼ同じであっても、それはそれでよいと言うのだ。
入れ子 Block にすべきか否か p230
こんな風に、一つのUIをHTMLとCSSで書くにも、Blockを入れ子にしたりしなかったりできるわけだが、
どういうケースで入れ子 Block にすべきかという判断は、なかなか一概に言えるものではない。
先程メリットで例に挙げた、枠組みの中にグラフやフォームなんかが入るという画面の例は、
入れ子 Block にしてしかるべきパターンだと筆者は思う。
確かにあのような場合、箱ごと Block にしてしまうと、CSS的に重複が多くなり、無駄に感じられてきそうだ。
枠組みで囲って情報を整理するのが、Webサイト全体で統一されたUIのルールみたいな事情があるのであれば、
枠と中身を分ける入れ子 Block による設計は、うまくマッチしていると言えるだろう。
これが、内容のバリエーションがほとんどない場合、 Block を入れ子にする必要性はかなり低い。
デメリットで挙げた、中身を全部別のBlockとして考えたmedia-blockの例について言えば、
本当になんでも入るようにしておく必要があるのか?というところを事前に考えるべきだろう。
設計の美しさみたいなところばかりに目を奪われてしまうと、何でも許容できるようにしておきたくなってしまうが、
実際にこういう風に何でも入るようにしておいたところで、そんなに色々入るのだろうか。
デザイン時には何でも入れられるようにしたいと思っても、実際に画面を作り出したら、
ほとんどただの段落とリストしかいれる必要がなかったみたいなことを、筆者はよく経験してきた。
前回紹介したECCS的な考え方に倣い、ある程度のコード重複であれば割り切って、別のBlockにした方がよい場合も多々ある。
Blockを入れ子にすることで得られることはあるが、少なくとも1段階、複雑さが増すということは頭に入れておかなければならない。
コンテンツやUIの設計と相談しつつ、入れ子Blockにすべきかどうか判断することをオススメしたい。
p232
<section class="recommend-block">
<h2 class="recommend-block__title">Google Chrome</h2>
<p class="recommend-block__text">すごいブラウザです</p>
<div class="recommend-block__nav">
<a class="button-primary" href="#">詳細はこちら</a>
</div>
</section>
筆者としては、このボタンのように、 HTML の構造的に単純なもの、
粒度の小さいまとまりであれば、積極的に単独のBlockとして考えたほうが、効率がよいことが多いと考えている。
Blockを入れ子にすることのデメリットとして挙げたのは、コードが複雑になってしまうということだった。
このボタンのように単独の要素で表現できるようなUIであれば、Blockが入れ子になっていることに対する複雑さはかなり低いと言える。
それに、このボタンのような要素は、Webサイト全体で見栄えを統一しておくことが多い。
それぞれのBlockの中にボタンのコードが書かれ、少しずつ高さや色が違ってしまったりするのは、大抵の場合望ましい状態とは言えないだろう。
ボタンを独立したBlockとして考えれば、そのような不整合は起こりづらい。
総じて、このように単純な構造のUIは、Blockの入れ子にして使うことで得られるメリットの方が大きいケースが多いと思われる。
p234
このような仕組みは WYSIWYG (What You See Is What You Get の略) と呼ばれ、
直接HTMLを書かずとも、ある程度の複雑さを持ったコンテンツを作れるため、多くのCMSで採用されている。
そのため、仕事でWYSIWYGで作られたデータをどうこうする機会は多い。
このWYSIWYGを採用する場合にポイントとなるのは、WYSIWYGにより作られたHTMLに対して、何かしらclass属性を指定したりすることは、基本的にできないということである。
BEM的には、それぞれの要素にクラスを付けたりしたいところであるが、それができない。
このようなケースでは、以下のように、WYSIWYGで入力されたコンテンツを包括するBlockを作ってしまうのがシンプルである。
<div class="richtext-block">
<h2>買い物リスト</h2>
<ul>
<li>にんじん</li>
<li>トマト</li>
<li>玉ねぎ</li>
</ul>
<p>彼は背後にひそかな足音を聞いた……</p>
</div>
p239
このユーティリティクラスというのは、汎用的にどこでも使えるものの、BEM的な設計から外れる存在なので、あまり多用しないことを勧めると書いた。
しかし、ユーティリティファーストの考え方に倣えば、まずはこれらユーティリティクラスを大量に用意する。
color、font-sizeやline-height、width、height、displayやfloatやらを制御するためのものまで、たくさん。
そして、なんとこれらだけを使ってHTMLを組み立てるのだ。
HTMLとCSSでコンポーネント化しない p244
こんな風に紹介すると、いいことばかりのように聞こえるだろうか。
「いやいやちょっと待って。じゃあ今までこの本に書かれていたBEMとかは何だったの?」と感じられるのではないだろうか。
その疑問は至極妥当である。
だって、色々自由に書いていくとうまくいかないから、BEMみたいなコンポーネントによる設計を採用しようとここまで解説してきたのだ。
それなのに、ユーティリティファーストの設計はまるで直接 style 属性で見栄えを定義しているのに近いではないか。
ユーティリティファーストの設計では、コンポーネントという概念を取り入れないのだろうか。
何かしら良いアイデアがあるんだろうと期待されるかもしれないが、
なんと、ユーティリティファーストの設計においては、HTMLとCSSを書く段階において、BEMのようなコンポーネント化をほぼ行わないことをポリシーとする。
この結果、あからさまなデメリットが発生する。
HTML上で重複がたくさん発生することである。
先程、ユーティリティクラスだけで書いたコードの例を紹介した。
あのUI、8個並べたかったらどうすればよいのか?
どうということはない、8回同じ、ユーティリティクラスだらけのHTMLを繰り返すだけである。
このコードを8回繰り返すとなれば、当然のことながら、少しスタイルを変えたい場合でも、8箇所すべてを修正しなければならないわけだ。
背景の白をオレンジに変えたかったらbg-whiteというクラスをbg-orangeに変えたりする必要がある。
これが 100 画面に存在していたらどうだろう、 100 画面 分のHTMLを編集しなければならない。
これは、普通にCSSを書いてきた人にとって、素直には受け入れ難いところだと感じられるのではないだろうか。
HTMLとCSSの外側でコンポーネント化する p246
Tailwind CSS では、まずユーティリティクラスを使ってHTMLを書き、
そこで繰り返されたりなど、何度も必要になるパターンが登場したら、そこで初めてコンポーネント化をするというフローを推奨している。
まず「ユーティリティクラスだけで書く」
そして「後から (必要なら) コンポーネント化する」である。
これはBEM的なアプローチとは正反対である。
なるほど?
それなら、まずはユーティリティクラスで書いた上で、後からBEMのような書き方に直すのかな?と思われるかもしれないが、そういうわけではない。
Tailwind CSS の勧めるユーティリティクラスという設計においては、HTMLとCSSのレイヤーでコンポーネントらしきものを作る、BEMのような設計をよい考えではないと考えている。
Tailwind CSS は、そういうコンポーネント化はHTMLとCSSの外側で行うことを勧めている。
そのためには、React、Vue.jsなどのコンポーネント指向のJavaScriptライブラリであったり、何かしらのテンプレートエンジンやCMSを使うことになる。
実装の要件は適切か p252
まず、実装の要件として、ユーティリティファーストで設計するのが適切かという判断が必要だろう。
ユーティリティファーストいいなーと思って安易に選択すると大変なことになりえる。
例えば、ただHTMLとCSSを手書きして大量の画面を作るようなケース。
これについては先程も少し触れたが何百ページもあるコーポレートサイトを作るが、取り立ててCMSを導入したり、
先述したReactやVue.jsベースで作るわけでもないようなケースを想像してもらいたい。
この場合にユーティリティファーストの設計を行うのはなかなか厳しいだろうと筆者は考える。
ここまでで紹介したReactやVue.js、もしくは何かしらのCMSなど、コードをコンポーネント化する仕組みがない状態だと、
ユーティリティクラスだらけのHTMLを何度も置換したりすることになるはずである。
これがいかに大変かは想像に難くない。
例えBEM的に書いていたって、CSSだけを直してUIの調整が完了しないことはよくある。
そういう場合、何百ページもあるようなプロジェクトでは、置換したり、直して回るのである。
ユーティリティクラスだらけのHTMLでそれをやろうとすれば、タブや改行の違い、クラスの順序違いなどで、もはや探すことすらできなくなる可能性は高い。
逆に、コンポーネント的な管理がHTML+CSSの外側でできる場合、設計の能力は求められるものの、
この懸念を払拭できるため、ユーティリティファーストという考え方は、比較的選択しやすい設計手法かと思われる。
おわりに p255
本書は「はじめに」に書いたとおり、企画のアイデアが出てから随分時間がかかってやっと書き終わったものであるが、
実は、執筆に本格的に取り掛かった時期から出版までにも2年くらいの時間が経っている。
CSS設計について言えば、この海に住んでいる生き物と同様、様々な形があり、
それが混在していると考えてもらえばよいのではないかと筆者は考える。
例えばクラゲ。
これは取り立てて何か考えず、ページごとになんとなくCSSを書いて成り立っている状態をイメージしてほしい。
そんなCSSで大丈夫か?と感じられるだろうか。
それは正しいが、駅前のお店の、5ページしかないWebサイトであれば別に何ら問題はない。
そして実際にクラゲがたくさん海に生きているように、そのように、チョチョイとCSSを書いて済ませているWebサイトも無数にある。