はじめに
こんにちは。フリーランスコーダーのなかざわです。
本記事は、私立探求学園アドベントカレンダー「私の爆速コーディング」記事の後編にあたる「設計思想・ルール編」です。
前編では物理的にコーディングを助けるツールをメインにご紹介しました!
本編では、HTMLの設計思想やHTML/CSSの記述ルールについてご紹介致します。
※ 以下、記事内のHTMLはHTML5(最新)を前提とした記法です。
※ ReactやVueなどのフレームワークを使うことを前提としない、あくまで「コーディングのベーススキルを上げる」ための記事となっています。あくまでコーディングスキルの成長途中として身につけてほしい基礎的な考え方です。より発展した設計思考については別記事でご紹介出来るように致します。
改めてコーディングに必要なこと
前編の振り返りですが、コーディングに必要なこと(コーダーに求められること)は以下でした。
- 文書的整合性
- ピクセルパーフェクト
- 作業の効率性 & メンテナンス性
☆ 文書的整合性は、HTMLの仕様の理解が大切ですが仕様を覚えきるのは大変です。ここはHTMLバリデートツールで補うことができることをお伝えしました。
☆ ピクセルパーフェクトは、デザイン画像を半透過させてブラウザに表示したページと重ねて確認出来るツールがあることをお伝えしました。
☆ 効率性を物理的に助けるツールも、厳選したものになりますがご紹介致しました♪
本編では、「作業の効率性 & メンテナンス性」についてをかなえるためのHTML設計思想や、HTML/CSSの記述ルールに集中してご紹介したいと思います。
慣れないなかでのコーディングは闇雲に書いても整合性がなかったり、他の人にとって(時に自分でさえも)読みにくい・管理しにくいコードになりがちです。
なんとか完成させても、あとでバグや更新があった時に「スムーズに・安全に」管理できる状態でなければ、結局書き直し・・・なんて残念なこともあります。
また、自分だけが永遠にコードを管理出来れば良いですが、実際には他のエンジニアに運用を引き継いだり、バックエンドエンジニアにコードを触ってもらうこともあるので、誰でも管理しやすいコードを書きたいですね。
ちょっとコツを掴めばコードは整合性を持ち、管理しやすくなってコーディング自体も楽になります。
**「メンテナブル(管理しやすさ)」**を意識したHTML設計を目指して周りの人も喜ぶ、自分も楽ちんなコーディングを習得してください!
メンテナブルコードとは
メンテナブルコード = 管理のしやすいコード とはどのようなコードのことでしょうか?
- 読みやすい・見やすい
- コードを読んですぐに理解できる
- 規則性がある
結論、シンプルなコードが管理しやすいです。
逆に
- コードが膨らみすぎている 【divタグ無駄に多くないですか?】
- なぜあるのか分からない要素・スタイル 【クラスの命名、的確ですか?】
- 整合性がなさそう、不安定に感じるコード 【なんとなく、で組んでいませんか?】
にならないように意識してみましょう!
HTML設計思想 「要素をブロックごとに分ける」
まずは、デザインやワイヤーフレーム (構成書)を確認する時に、ざっと「どう組むか」を頭の中で考えてみましょう。
その時に、各要素を「ブロック」に分けることを意識します。
ブロックとは・・・
- 「ひとかたまり」の単位
- 独立しているもの = 単体で成り立つ(表示的な面 / マークアップ&情報の意味的な面)
ちょっと難しいですね。。
クラス命名をBEMに頼ってみる
BEMとはクラスの命名規則のひとつですが、
HTMLの設計思想としても頼れるものです。
参考文献
BEMを用いることで、 「要素をブロックごとに分ける」という考え方を身に付けられるので、クラス命名が自由にできる機会があれば、ぜひBEMで書いてみてください。
BEMでの命名はBlock, Element, Modifire で構成されます。
-
Block ・・・ 要素のひとかたまり 形式は
.{block}
-
Element ・・・ Blockを構成する要素・またはBlockを構成するElementの中に入れ子でElementが置かれることもある。 形式は
.{block}__{element}
-
Modifire ・・・ Block や Block__Elementのパターン違い
--{modifier}
が接尾する
少しややこしいですが、Blockの中にBlockが入ることもあります。
Blockを構成するものはElementか、また別のBlockということですね!
Elementの中にElementが入っていることもあります。しかしBlock無しでElementだけで存在することはありません。
このあたりは実際に書いてみないと感覚が掴みにくいと思うので、深く考えなくてもよいです♪
Modifierについては、後で改めて説明しますので、一旦は気にしなくて良いです。
デザインを見た時に、まずは「どれがBlockか」を考えて、Blockを見つけられたらそのBlockを構成する中身についてを考えるようにしましょう!
レイアウトレベルのBlock分け
例えばこのようなページデザインだったら、まずはレイアウトレベルでざっくりとBlock分けをします。
- Headerのブロック
<header class="header"></header>
- Main contentのブロック
<main class="main"></main>
- Footer のブロック
<footer class="footer"></footer>
の3つに分けられます!
早速HTMLファイルに書いちゃいましょう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header class="header"></header>
<main class="main"></main>
<footer class="footer"></footer>
</body>
</html>
※ Headerブロックをheaderタグ、Footerブロックがfooterタグなのは異議が無さそうですが
Header, Footer以外の部分(この場では「Main content」と呼びました)の解釈と、そこにどのタグをあてるかは実装者によって異なるところかと思います。
ここではよりシンプルに考えたいので、敢えてmainタグをあてて、ブロック名もタグに合わせてmain
にしました。
ブロックの中の要素分けをする
ブロックに分けられたら、一つ一つのブロックの中に注目して、そのブロックを構成するものをさらに分けます。
今回はHeaderブロックでやってみましょう。
まずデザインのHeaderに注目します。
Headerの中には「Logo」と「Navi」があることが分かりました。
この2つの要素でHeaderを構成しているんですね!
「Logo」と「Navi」はブロックを構成する要素なので、Elementとして命名できます。
<header class="header">
<div class="header__logo">
<img src="logoImagePath" alt="Logo" />
</div>
<div class="header__navi">
// ナビの中身☆
</div>
</header>
いかがでしょうか?
すっきりまとめられていますね。
.header__logo
の中には、Logo画像を入れるための<img>
タグも入れておきました。
.header__logo
の中はもうこれ以上HTML要素の追加は要らないですね。src=""
属性で画像の指定をして、CSSで表示を調整するだけです。
ですが.header__navi
は、ナビの中身の要素を入れないと成り立ちません。
ナビの中を確認すると、他ページへの遷移するリンクが5点あります。
つまり少なくとも5点の要素を.header__navi
の中に入れないといけません。
では、その5点はそれぞれどのようなタグで、どのように命名したクラスをつけるべきでしょうか。
・・・
まず、タグを決めましょう。
今回のナビの中のアイテムは「同一のレベルの要素が並んでいる」と言えるため、ul
, li
タグで管理したいです。
では、ul
, li
タグでナビの中身を組んでみましょう!
ページ遷移リンクであることを見越して、li
の中にa
タグも入れておきました。
<header class="header">
<div class="header__logo">
<img src="logoImagePath" alt="Logo" />
</div>
<div class="header__navi">
<ul>
<li>
<a href="dammy">About</a>
</li>
<li>
<a href="dammy">Sample Page</a>
</li>
<li>
<a href="dammy">Product</a>
</li>
<li>
<a href="dammy">Access</a>
</li>
<li>
<a href="dammy">Contact Us</a>
</li>
</ul>
</div>
</header>
このようになります。思ったより記述量が増えますね。
ここで私のコーディング規則があります。
ul
タグなどのリスト系タグには必ず・・・list
という単語を入れたクラスを付ける
あくまで私の中での絶対ルールですので、取り入れなくても良いです。
ですが、このように規則を持ってコーディングすると一貫性を持ち、悩む時間も減って作業スピードが上がります。
合理的な規則を自分で作る・・・というのは難しいです。変なクセになったり、諸刃の剣でもあります。
他のエンジニアに「どうして?」と理由を聞かれたときに説明できる規則にしましょう。(そもそも「どうして?」って聞かれた時点で、他人に意図が伝わりにくいということなので、その規則が本当に良いのかを考えたほうが良いかもしれません。)
上記のルールによって、.header__navi ul
のクラス名はlist
という単語が付くと決まり、命名が少しだけ楽になりました。
では、クラス名を完成させましょう!
先に大きなヒントですがol
やul
、dl
のリストタグのほとんどはElementです。(.xxxx__list
という形になるということですね)
なぜかというと、これらリストはあくまで「何か」のためのリストだからです。「何か」を構成するリスト要素です。
その「何か」がBlockにあたります。
では、今回のul
が「何の」ためのリストか、一度考えてみてください♪
(困ったらデザインを俯瞰・・・)
「Naviのためのリスト」ですね。
(さらには「Headerを構成しているNaviのためのリスト」です。)
ということで前回のHTMLコードでdiv
タグ.header__navi
だったところを.navi
に。その中にul.navi__list
を入れましょう。
☆Point
div
タグ.navi
はさっきまで.header__navi
でした。
このdiv
が「Naviブロック」であり、「Headerを構成するNaviエレメント」だからどちらのクラスも存在できそうですよね。
ですが、このようにBlockクラスとElementクラスが競合した場合には、Elementクラスは不要ですので削除してください。(Blockが勝っちゃいます。)
「マルチクラスを避ける」ことを意識しましょう。
ul
までクラス命名がされていれば、その子要素であるli
はクラスの命名が不要です。.navi__list li
のセレクタを使いましょう。
<header class="header">
<div class="header__logo">
<img src="logoImagePath" alt="Logo" />
</div>
// 以下はもともと`.header__navi`だったがNaviはブロックだと定義したため、
// `.navi`に命名を変更。マルチクラスを避けるため`.header__navi`の命名は削除。
<div class="navi">
<ul class="navi__list">
<li>
<a href="dammy">About</a>
</li>
<li>
<a href="dammy">Sample Page</a>
</li>
<li>
<a href="dammy">Product</a>
</li>
<li>
<a href="dammy">Access</a>
</li>
<li>
<a href="dammy">Contact Us</a>
</li>
</ul>
</div>
</header>
どうでしょうか?
コードの中で「何の要素があるか」が見やすくなっていると思います。
今回は.header
ブロックが.header__logo
エレメントと、.navi
ブロックというまた別のブロックによって構成されているという設計にしました♪
同様に.main
と.footer
ブロックも分解します。
BEMを取り入れたHTML設計まとめ
- まずはどんどんデザインからBlock分けをする
- Block分けをしたら、Blockの中の要素をさらにBlock / Elementに分ける
- 頭の中で1.と2.が出来たらどんどんコードに反映する
この要素はBlockなのかElementなのか分からない・・・
迷ったら、以下を確認してみましょう。
① その要素は単体で成り立つか(表示的な面 / マークアップ&情報の意味的な面)
② その要素の自体が複数要素で構成されそうか・要素の中身が膨らみそうか
この問がそれぞれYESだったらBlockで良いです。
☆Point
特に①がYesの場合は迷わずBlockと判断して良いです。
②は必ずしもBlockの中の構成要素が多いとは限らないので一概には言えませんが
逆にElementの構成要素は少なくシンプルであるべきなので、Elementのつもりだったのに中の要素が膨らんでしまう場合には、Blockとして管理出来ないかを検討してみてください。
一つのクラスに一つの役割・マルチクラスを避ける
直前のHTMLコードのコメントアウトにも記載したとおり、必要性がない限りはマルチクラスを避けます。
1つの要素に対してクラスが複数存在すると、一つの要素に対して複数方向からスタイルの指示が出来るため
「なぜこの要素がこの表示になっているのか」の理由が分かりにくくなります。
<header class="header">
<div class="navi header__nav">
<ul class="navi__list">
<li>
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
このようなHTMLになってしまうと、クラス.navi
と.header__navi
が同じ要素に存在しているせいで、
どちらのクラスにスタイルを当てるか迷いませんか?
また、気づかないうちに複数から同じ要素に対してスタイル指定をしてしまって、すぐに気づかないと混乱します。
このスタイル指定も、どちらも同じ要素に対して指定していますが、ぱっと見ても分かりにくいですよね。
.header .header__navi {
font-size: 20px;
}
.navi {
font-size: 24px;
}
このことから、必要性のないマルチクラスを付けないように気をつけます。
マルチクラスが必要なパターン
ここでBEMのうちのM、Modifierが出てきます。
Modifierは装飾を表すクラスで、BlockまたはElementの後ろに--modifier
が付く形式です。
そして必ずマルチクラスで用いるというBEMのルールがあります。
どのような使い方をするのかというと、
例えばButtonブロックで色だけの違いがあるパターンがあった場合
<div class="button">プロジェクト内でベーシックなブルーのボタン</div>
<div class="button button--red">色違い赤のボタン</div>
.button {
/* Modifierがない元のクラスのスタイルには`.button`の見た目に必要な基本のスタイルが全て入っている */
display: block;
width: 300px;
padding-top: 20px;
padding-bottom: 20px;
background-color: blue;
color: #fff;
font-size: 20px;
}
.button--red {
/* 色違いに必要なプロパティだけを入れる */
background-color: red;
}
このように書きます。
Modifierクラスである.button--red
はそれだけでは存在できずModifierが付く元となる.button
と一緒のマルチクラスとなります。
この時.button
ブロック側のCSSで、ベースになるスタイル揃うように指定しておきます。
そうすることでModifierクラス側ではパターン違いに必要なスタイルだけ書けば良くなるのです。
CSSスタイル思想 「とにかく見やすく・触りやすいCSS」
ここからはCSS側のワンポイントとアンチパターンについてご説明します。
どれも地味ですが、こういうものが積み重なって見やすく触りやすいCSS = 作業の効率化になります。
ショートハンドを避ける
CSSプロパティと値の書き方についてです。
ショートハンドというのは「省略した書き方」のことです。
複数のプロパティを一つにまとめられて便利ですが、メンテナンス・デバッグ性の観点からオススメしていません。
例えば、よく用いられるショートハンドはmarginやpaddingだと思います。
h2 {
margin: 10px 8px;
/* 以下を省略しているショートハンド
margin-top: 10px;
margin-bottom: 10px;
margin-right: 8px;
margin-left: 8px;
*/
}
4行が1行になるのでとてもスッキリして見えますね。
ですが、後でmargin-leftだけ12pxに変えたい時にはどうしますか?
あるいは、値すら決まっていなくてデザインに合わせながら少しずつ変更して検証したいこともあります。
ショートハンドだと、微調整や変更が入る時に書き直しにくいことがあり、
場合によってはせっかくショートハンドで書いたのに、結局ショートハンドではない正規の書き方に変更しないといけなくなることが起こり得ます。
他にもショートハンドではなく正規のプロパティ指定ができると
- ぱっと見た時にプロパティとプロパティ値が1対1になっているほうが、何がどこで指定されているかが分かりやすい
- ブラウザのDevツールで調整・検証する場合にも、ショートハンドではないほうが値の変更がスムーズになり開発効率があがる
というメリットがあります。
ショートハンド推奨派の方や現場もありますので、一概には言えませんが私のコーディング思想としてはショートハンドを使わないことをオススメしています。
scss記述のタブーを避ける
前編でご紹介したscss
は様々なセレクタの指定方法があり、記述量の省略になります。
ですが、一部タブーとされるscss
セレクタの書き方がありますのでお気をつけください。
クラス名を途中で分断する&
のタブー
.header {
/* セレクタ .header__text */
&__text {
font-size: 20px;
}
}
「scss
の書き方」で検索すると、この書き方がよく紹介されています。
もちろん、scss
記法としては誤りではありません。
ですが、メンテナンス性から見るとアンチパターンだと言えます。
自分で作ったWebサイトであれば、「このタイトル部分のスタイルを変えたい」となった時に
タイトル部分のクラス名を確認して、そのクラスに対するスタイルがどこに書いてあるのかをなんとなく把握している場合もあると思います。
しかし、大きなサイト且つ他人が制作したサイトの編集を行わなくてはならなくなったとき。
編集したい部分のクラス名をまず確認します。
例えば上の例のように.header__text
だとして、これに当てているスタイルがどこに書いてあるかすぐに分かりますか?
大きなサイトの場合、scss
だけでも数千行あったり、その記述が複数ファイルに分散されて管理してあることもあります。
そのため、クラス名からスタイルの記述場所を推測するより、クラス名でプロジェクト内検索したほうが良いです。
しかし、上記の様にセレクタのクラス名を途中で分断していると、検索すらできなくなります。
.header__text
で検索しても
.header {
&__text {
font-size: 20px;
}
}
ここにはたどり着けないですよね。
これが、アンチパターンと呼ばれる理由です。
検索性・参照性が低くなるような記述は避けましょう!
クラス名を途中で分断するような&
の使い方はせず、
以下のように書けばクラス名で検索して検出できます。
.header {
.header__text {
font-size: 20px;
}
}
では&
はどのように使うのかというと、Modifierのマルチクラスを表す時や:hover
、::before
の時です。
&
を付ける元のセレクタに、状態を追加したい時のスタイルに用いいる事が多いです。
こちらは、Modifierの説明のときのCSS
をscss
にした場合の書き方です。
.button {
display: block;
width: 300px;
padding-top: 20px;
padding-bottom: 20px;
background-color: blue;
color: #fff;
font-size: 20px;
/* 擬似クラスの書き方
.button:hover */
&:hover {
opacity: .7;
}
/* マルチクラスの書き方
.button.button--red */
&.button--red {
background-color: red;
}
}
scss
特有の記法に慣れない場合には、複雑になりそうなセレクタ記述にはせず、クラス名を分断しないことだけを意識してみましょう!
プロパティの記述順を統一する
こちらはおすすめしていることです。
CSSでのスタイル指定でプロパティの順番を意識できていますか?
以下のCSSを見て、ムズムズする〜と思う?思わない?
.article__header{
color: red;
display: block;
font-size: 40px;
margin-top: 30px;
}
/* Element内の複数単語はケバブケース */
.article__more-button {
display: block;
margin-top: 50px;
color: blue;
font-size: 20px;
}
プロパティの順番を意識できていると、上のCSSを見て「むず痒い」気持ちになると思います。
プロパティの指定順が毎度バラバラだからです。
color
プロパティが最初に指定されているセレクタがあれば、後ろのほうに書かれているセレクタがあったり。
規則性がなく、毎回順番が異なると、書いているときは良いですが後でスタイル変更があったときにプロパティを探す時間が生まれます。
ぱっと見たときの「見やすさ」と最終的な「触りやすさ」に欠けてしまうのです。
とはいえ、もともとはプロパティの指定に順番は関係ないため、個人の中で一貫性・規則性を持って制作・管理できれば良いと思います。
「厳密に並べろ」というよりは、「いつも冒頭にあるはずのdisplay
が下にあるのはちょっと気になるな」くらいでも良いです。
少しずつ順番を統一出来るように意識してみてください。
参考文献
私は今回の記事を書くまで知りませんでしたが、mozillaがCSSプロパティの順番について提唱しているようです。
参考サイトはその内容を簡単にまとめてくれている記事です。ぜひ参考にしてみてください。
おそらくこれが巷のベーシックとなっていて、本業コーダーさんはこの順が多いと思います。
イメージ的には、要素のブロックの外のプロパティから順に書いていく、という感じですね。
完全に覚えるのは大変だと思うので、これをベースにしながら記述の統一を目指しましょう!
扱いやすい言語だからこそ、設計・管理にこだわりを
HTMLとCSSは比較的扱いやすい言語だと思います。
軽い理解である程度は形にできますよね。
そのため、普段はシステム側の開発を本業としていてメインではないけどHTMLを触ることがあるよって方もとても多いと思います。
様々な背景で触る人がいて、理解レベルももちろんバラバラです。
だからこそ、私たち本業コーダーは誰が見ても分かりやすい・触りやすいコードを目指しています。
規則性を持つことについて、特に巷で認識されている既存の規則にならうことについては
例えば誰かにコードを共有しなくてはならないときに、「これはxxxという規則にならって制作しています」と一言伝えるだけで相手のコードの読みやすさは向上しますし、HTML界隈の理解が深い人であれば、規則性を伝えなくてもコードを見ただけで規則を理解してもらえる場合もあります。
自分自身にとっても、今回のBEMやmozilla.org Base Stylesなどの規則に頼ることで考える部分が少し減って、その分他のところにエネルギーを使えるようになります。
慣れるまでは逆に時間や手間がかかるように感じるかもしれませんが、慣れたら少しずつコーディングが楽になっていくはずです。
コーディングのコツが掴めないな〜という方は、ぜひBEMコーディングにチャレンジしてみてください。
BEMに慣れて設計が楽になってきたら、より楽ができる方法がないかを探してみてください。
さらに合理的な設計がないかを探すのも良いですね!
PDCAを回しまくって、コーディングを極めていきましょう!
(今回の内容については一つの記事にまとめるのに無理がありました・・・。それぞれの詳細記事を今後、別の記事としてかけるようにしておきます!)