Skip to content

HTMLガイドライン

🔰 当ドキュメントは「コーディングガイドライン」の一部です。 基本的なガイドライン・ルールについては先にそれから確認してください。

🎯 HTMLガイドラインの目的

HTMLのガイドラインは次の3つを主な目的として規定します。

  • セマンティック・アクセシビリティ
    • コンテキスト(文章などの前後の脈絡・文脈)によって最適なマークアップができること
    • 普遍的でアクセシブルなマークアップができること
  • 一貫性
    • 一貫したルールがあることで個人の好みや矜持による品質のバラツキを抑えること
    • プロジェクトをまたいでも混乱が少ないこと
  • メンテナンス性
    • デザインの変更に対して柔軟で応用が効く汎用的な作りであること
    • コンポーネントの単位で影響範囲を把握しやすく管理できること

HTMLの品質を支える規格

次の規格やガイドラインを参考に最適な実装をしていきます。

HTML Living Standard

原則としてHTML Living Standardの規定は例外なく従います。

WAI-ARIA

WAI-ARIAはWAI-ARIA 1.2を基本に、ブラウザや支援技術の実装状況を鑑みながら判断します。

WCAG (Web Content Accessibility Guideline)

WCAG 2.2の4原則(知覚可能、操作可能、理解可能、堅牢性)に基づいてマシンリーダブルなマークアップをします。

APG (ARIA Authoring Practices Guide)

ARIA Authoring Practices Guide (APG)を参考にUIを実装します。特にARIA属性やキーボードの操作については特別な理由がない限りこれに則って実装します。

💅 コードスタイル

editorconfigMarkuplintpug-lintPrettier それぞれに設定されているルールに則って記述します。エディタやコマンド実行時に警告が出た場合は必ず修正してください

各設定は以下のパッケージを利用しています。

リントエラーについて

例外なく必ずリントエラーを修正してください。リンターのルールが現状にそぐわない場合はルールの見直し、つまりConfigファイルの変更を行ってください

改行・インデント

原則、ネストしたタグは改行・インデントしてください。親子・兄弟関係を明確にし、エディタのコード折りたたみ機能が有効になり、コードの読みやすさに繋がります。ただし、要素のスタイルがインライン(inlineinline-blockなど)で、前後のホワイトスペースがレンダリングに影響を及ぼす可能性のあるタグについてはこの限りではありません。

コード例
html
<!-- ✅ 良い例 -->
<ul>
	<li>apple</li>
	<li>orange</li>
	<li>banana</li>
</ul>

<!-- ❌ 悪い例: インデントされていない -->
<ul>
<li>apple</li>
<li>orange</li>
<li>banana</li>
</ul>

<!-- ❌ 悪い例: インデントが揃っていない -->
<ul>
	<li>apple</li>
<li>orange</li>
	<li>banana</li>
</ul>

<!-- ✅ 良い例: インラインの要素は改行とインデントの必要はない -->
<div>
	<p>This apple is <strong>red</strong></p>
</div>

<!-- ✅ 良い例: インラインの要素は改行とインデントの必要はない -->
<ul>
	<li><a href="/apple/">apple</a></li>
	<li><a href="/orange/">orange</a></li>
	<li><a href="/banana/">banana</a></li>
</ul>

<!-- ❌ 悪い例: 明らかにa要素はインラインでない -->
<a href="/path/to/link"><div>
	<img src="/path/to/image.png">
	<p>lorem...</p>
</div></a>

<!-- ✅ 良い例: 明らかにa要素はインラインでない -->
<a href="/path/to/link">
	<div>
		<img src="/path/to/image.png">
		<p>lorem...</p>
	</div>
</a>

🔧 自動修正可能

このルールはPrettierによって自動修正されます。

タグ

  • タグ名や属性名は小文字を使用します
  • 空要素の開始タグの末尾に/(スラッシュ)を記述します
  • 終了タグは省略しません
コード例

タグ名や属性名は小文字を使用します。

html
<!-- ✅ 良い例 -->
<a href="/path/to/link">...</a>

<!-- ❌ 悪い例 -->
<A HREF="/path/to/link">...</A>

ただし SVG(インラインSVGも同様)は属性名の大文字小文字を区別するため、仕様に従います。

html
<!-- ✅ 良い例 -->
<svg viewBox="0 0 400 300">...</svg>

<!-- ❌ 悪い例: svg要素は正しく大文字小文字を指定しないと動作しない -->
<svg viewbox="0 0 400 300">...</svg>

空要素の開始タグの末尾に/(スラッシュ)を記述します。本来必要ありませんが、Prettierの挙動に従います。

html
<!-- ✅ 良い例 -->
<img src="/path/to/image.png" />

<!-- ❌ 悪い例 -->
<img src="/path/to/image.png">

終了タグは省略しません。

html
<!-- ✅ 良い例 -->
<ul>
	<li>apple</li>
	<li>orange</li>
	<li>banana</li>
</ul>

<!-- ❌ 悪い例 -->
<ul>
	<li>apple
	<li>orange
	<li>banana
</ul>

🔧 自動修正可能

このルールはPrettierによって自動修正されます。

属性値の引用符

属性値の引用符に"(ダブルクォーテーション)を使用します。

コード例
html
<!-- ✅ 良い例: 属性値の引用符にダブルクォーテーションを使用している -->
<a href="/path/to/link">...</a>

<!-- ❌ 悪い例: 属性値の引用符にシングルクォーテーションを使用している -->
<a href='/path/to/link'>...</a>

<!-- ❌ 悪い例: 属性値に引用符を使用していない -->
<a href=/path/to/link>...</a>

ただし、属性値に"を記述する場合は、属性値の引用符に'(シングルクォーテーション)を使用します。

html
<!-- ✅ 良い例: 属性値にダブルクォテーションが含まれているため、属性値の引用符にシングルクォーテーションを使用している -->
<a href="/path/to/link" title='This title includes "double quotation".'>...</a>

<!-- ❌ 悪い例: 属性値にダブルクォテーションが含まれているのに、属性値の引用符にダブルクォーテーションを使用している -->
<a href="/path/to/link" title="This title includes "double quotation".">...</a>

🔧 自動修正可能

このルールはPrettierによって自動修正されます。

論理属性

論理属性の値は省略します。

html
<!-- ✅ 良い例 -->
<input type="checkbox" disabled />
<input type="checkbox" checked />

<!-- ❌ 悪い例 -->
<input type="checkbox" disabled="disabled" />
<input type="checkbox" checked="checked" />

属性の省略

省略可能な属性は省略します。

html
<!-- ✅ 良い例 -->
<link rel="stylesheet" href="/path/to/style.css" />
<script src="/path/to/script.js"></script>

<!-- ❌ 悪い例 -->
<link type="text/css" rel="stylesheet" href="/path/to/style.css" />
<script type="text/javascript" src="/path/to/script.js"></script>

Pugの属性

  • id属性は#リテラルを使用します
  • class属性は.リテラルを使用します
  • 属性は次の順番で記述します
    1. id属性
    2. class属性
    3. class/id以外の属性
コード例
pug
//- ✅ 良い例
div#id-name.c-class-name(data-attr="value")

//- ❌ 悪い例: class属性に.リテラルを使用しておらず、順番に従っていない
div(data-attr="value" class="c-class-name")#id-name

🔧 自動修正可能

このルールはPrettierpug-lintによって自動修正されます。

文字参照

次に挙げる文字はHTMLの特殊文字です。これらの文字をコードとして解釈させず、文字として表示したい場合、文字参照を使用します。

文字文字参照
<&lt;
>&gt;
&&amp;
"&quot;
'&apos;

特に、URL内の&&amp;と記述します。

html
<!-- ✅ 良い例: &が文字参照になっている -->
<a href="/path/to/link?key1=val1&amp;key2=val2">...</a>

<!-- ❌ 悪い例: &が文字参照になっていない -->
<a href="/path/to/link?key1=val1&key2=val2">...</a>

可読性のため、上記以外の文字に文字参照を使用する必要はありません。例えば、コピーライトマークは&copy;ではなく©と記述します。

html
<!-- ✅ 良い例: ©をそのまま記述している -->
<p><small>© 2024 D-ZERO Co., Ltd.</small></p>

<!-- ❌ 悪い例: &copy;を記述している -->
<p><small>&copy; 2024 D-ZERO Co., Ltd.</small></p>

Pugの文字参照

Pugでは属性値の文字参照は自動で行われるため、手動で記述する必要はありません。

pug
//- 入力
a(href="/path/to/link?key1=val1&key1=val1")
html
<!-- 出力 -->
<a href="/path/to/link?key1=val1&amp;key2=val2"></a>

コメント

<!-- の後と --> の前にはスペースまたは改行を記述します。

html
<!-- ✅ 良い例: ハイフンとコメント文の間にスペースがある -->
<!-- コメント -->

<!-- ❌ 悪い例: ハイフンとコメント文の間にスペースがない -->
<!--コメント-->

🔧 自動修正可能

このルールはPrettierによって自動修正されます。

🤔 コメントを書くかどうか

HTMLに記述したコメントは、製品ソースコード上に残るためエンドユーザが見える状態になります。 そのため、なるべく不用意なコメントは控えたほうがよいです。 CMSへの組み込みなどでメモ代わりに利用する場合は、組み込みの際に消してもらえるように依頼をしてください。

また、PugではHTMLに変換した際に削除されるコメント記法があるので、そういったものを積極的に活用してください。

📂 ファイル構成

ファイルは以下の構成で管理します。

# 開発ソースコード

📂 __assets/
├── 📂 htdocs/
│ ├── 📂 __tmpl/
│ │ ├── 000_home.pug
│ │ ︙
│ │ └── 302_form_complete.pug
│ ├── 📂 sub-dir/
│ │ ├── sub01.pug
│ │ ︙
│ │ └── sub99.pug
│ ├── index.pug
│ └── maintenance.html
└── 📂 _libs/
    ├── 📂 component/
    │ ├── header.pug
    │ └── footer.pug
    ├── 📂 data/
    │ ├── helper.js
    │ └── index.yaml
    └── 📂 mixin/
    └── meta.pug

# 製品ソースコード

📂 htdocs/
├── 📂 __tmpl/
│ ├── 000_home.html
│ ︙
│ └── 302_form_complete.html
├── 📂 sub-dir/
│ ├── sub01.html
│ ︙
│ └── sub99.html
├── index.html
└── maintenance.html

__assets/htdocsフォルダ構造を維持したままにドキュメントルートにあたるhtdocsに出力されます。最終的に整形されたHTMLファイルをするため、開発ファイルはPugでもHTMLでもどちらでも構いません

_libs/components_libs/mixinフォルダはPugで利用する断片要素、_libs/dataフォルダはPugから参照できるオブジェクトや関数を管理します。

🍴 プリプロセッサー・コンパイル環境

@d-zero/builderを通してPugからHTMLへの変換を行います。

製品ソースコードの納品要件によっては、改行コードや文字コードの変換が必要なケースがあります。その場合はeleventy.config.mjsに変換オプションを追加してください。

js
import path from 'node:path';

import eleventy from '@d-zero/builder/11ty';

export default function (eleventyConfig) {
	return eleventy(eleventyConfig, {
		alias: {
			'@': path.resolve(import.meta.dirname, '__assets', '_libs'),
		},
		outputCssDir: 'css',
		outputJsDir: 'js',
		outputImgDir: 'img',
		imageSizes: { selector: '*' },
		prettier: false,
		minifier: { minifyJS: false },
		lineBreak: '\n', // or '\r\n'
		charset: 'utf8', // or 'shift_jis',
		pathFormat: 'preserve', // or 'file' or 'directory'
		autoDecode: false, // or true
		ssi: {
			'**/*': {
				encoding: 'utf8', // or 'shift_jis',
			},
		},
	});
}

変換オプション

@d-zero/builder/11tyからインポートしたコンフィギュレーション関数eleventy()の第二引数にオプションを渡します。

alias

パスのエイリアスを設定します。

Pugでは@に指定したパスがルートとして解釈されます。次のパスは同じ場所を参照します。

ファイルベースディレクトリへの参照
Puginclude /same-dir/a.pug
SASS@import '@/same-dir/a.scss'
TypeScriptimport {} from '@/same-dir/a.js'

imageSizes

画像のwidth/height属性を自動付与します。selectorオプションにCSSセレクタを指定することで、対象範囲を限定することができます。

prettier

Prettierによる整形を行います。デフォルトはtrueです。

minifier

HTMLMinifierによって最適化を行います。必要であれば設定を上書きしてください。

lineBreak

改行コードを変換します。CRLF\r\n)やLF\n)を指定してください。デフォルトはLF\n)です。

charset

HTMLを出力する際に文字コードを変換します。文字コードはUTF-8utf8)とShift-JISshift_jis)のみ対応しています。デフォルトはUTF-8utf8)です。

overridesオプションで特定のファイルに限定することが可能です。

js
eleventy(eleventyConfig, {
	charset: {
		encoding: 'utf8', // グローバル設定
		overrides: {
			paths: ['legacy/pages/**/*'],
			encoding: 'shift_jis', // 特定のページへの設定
		},
	},
});

pathFormat

出力ファイルの形式を変更します。デフォルトはpreserveです。

説明
file各ページに対応するHTMLファイルを生成
directoryディレクトリを生成しページに対応するindex.htmlファイルをネスト
preserveソースフォルダに表示される通りにHTMLファイルを生成

この設定はAstrobuild.formatを参考にしています。

開発用ローカルサーバーのオプション

autoDecode

自動デコードを有効にします。開発用ローカルサーバーはUTF-8しか対応していないため、Shift-JISのファイルを開いた場合に自動でUTF-8に変換します。

ssi

開発用ローカルサーバーでSSI(Server Side Includes)を再現する設定です。簡易的なものになるので#includeディレクティブのみに対応しています。文字コードを自動で判定できないのでUTF-8以外に変更する必要がある場合は、対象ファイルのパターンに対してencodingを指定します。

📜 DOCTYPE

DOCTYPEは記述します。旧来の文書型宣言は使用しないでください。また、XML宣言は記述しません。

html
<!doctype html>
<html>

記述がない場合、ビルド時に自動で付与されます。

🔖 メタ要素

ビューポート

user-scalableは無効なため記述しません。

html
<meta name="viewport" content="width=device-width" />

その他の必須要素

html
<!-- 数字の連続が電話番号に変換されるのを抑制する -->
<meta name="format-detection" content="telephone=no" />

🔗 パスとリンク

hrefsrc属性に記述するパスは、原則 / (スラッシュ)で始まるルート相対パスで記述します。 これはCMSなどの動的に生成されるページでも、どの階層からでも同じリンク先を参照できるようにするためです。

html
<!-- ✅ 良い例 -->
<a href="/path/to/link">...</a>

<!-- ❌ 悪い例 -->
<a href="path/to/link">...</a>
<a href="./path/to/link">...</a>
<a href="../path/to/link">...</a>

ページ内リンク

URLのパスと同様に、id属性の値(URLのフラグメント)は適切に命名してください(👉識別子の命名規則)。また、安易に削除・変更しないでください。たとえページ内リンクを使用していなかったとしても、外部からリンクされている可能性があります。id属性の値を(安易に)削除・変更すると、ユーザーにとってはリンク切れと似た状態となります。

html
<!-- ✅ 良い例 -->
<a href="#about">...</a>
<section id="about"></section>

<!-- ❌ 悪い例: 不適切な命名をしている -->
<a href="#foo">...</a>
<section id="foo"></section>

外部リンク

ソースコードの検索性を上げるために//で始まるパスは避け、https://で開始してください。

必要に応じて、target="_blank"rel="noreferrer"、その他の属性を指定してください。ただし、target="_blank"を指定すると、暗黙的にrel属性にnoopenerを指定した場合と同様の挙動になるので、明示的にrel属性にnoopenerを指定する必要はありません。

html
<!-- ✅ 良い例 -->
<a href="https://www.d-zero.co.jp" target="_blank">...</a>

<!-- ❌ 悪い例 -->
<a href="//www.d-zero.co.jp" target="_blank">...</a>

セルフホストリソースと外部リソース

セキュリティや堅牢性のために外部リソースの読み込みは原則禁止します。CDNサーバのダウン、CDNの乗っ取り、サービス終了などの可能性があるのでできるだけセルフホストしたリソースを用います。ただし、クライアントの依頼または社内の許可がある場合に限り、外部リソースの読み込みを許容します。Google MapsやGoogle Fonts、その他ASPなどセルフホスト不可能なリソースはこの限りではありません。

html
<!-- ✅ 良い例 -->
<script src="/path/to/script.js"></script>
<link rel="stylesheet" href="/path/to/style.css" />

<!-- ❌ 悪い例 -->
<script src="https//www.example.com/script.js"></script>
<link rel="stylesheet" href="https//www.example.com/style.css" />

💎 コンポーネント

ページを構成するパーツをコンポーネントという単位で管理します。

これはスタイルシートのための規定であり、以下のような問題を未然に防ぐことを目的としています。

  • クラス名のコンフリクト(重複)および予期しないスタイル上書き
  • スタイル変更による子孫要素への予期しない影響

コンポーネントの構成とクラス命名規則

コンポーネントはそれ自身であるコンポーネントルートと子孫要素となるエレメントで構成されます。

BEMとの違い

基本的に似た概念をもちます。

BEMの概念ディーゼロの概念
Blockコンポーネント
Elementエレメント
Modifier状態

と捉えて差し支えありません。classの命名規則はBEMの本家とは異なります。

コンポーネントルートはクラス名によって明示的に定義され、【c- + コンポーネント名】というclassをもちます。 要素の種類・class以外の属性に関しては、コンポーネントに最適なものを選択しマークアップします。(👉セマンティックとアクセシビリティ

html
<!-- "header"コンポーネントの場合 -->
<header class="c-header"></header>

コンポーネントはコンポーネントを内包することができます

html
<!-- "header"コンポーネントの場合 -->
<header class="c-header">
	<!-- ❗内包される"nav-global"コンポーネント -->
	<nav class="c-nav-global"></nav>
</header>

コンポーネントルートの子孫要素は、コンポーネント以外はエレメントとなります。エレメントのclassは【c- + コンポーネント名 + __ + エレメント名】という命名規則でつけます。※ただしこのclassはスタイルシートのために必要なもので、エレメントに対しては必ずしも必要なわけではありません。classのないエレメントが存在してもかまいません。

html
<!-- "header"コンポーネントの場合 -->
<header class="c-header">
	<div class="c-header__body">
		<div class="c-header__title">
			<h1 class="c-header__site-name"><span>サイト名</span></h1>
			<p class="c-header__description">概要文</p>
		</div>
		<div class="c-header__info">
			<ul class="c-header__links">
				<!-- ❗classのないエレメント -->
				<li>
					<a href="/about-us/"><span>我々について</span></a>
				</li>
				<li>
					<a href="/sitemap/"><span>サイトマップ</span></a>
				</li>
			</ul>
			<a class="c-header__tel" href="tel:0000000000"><span>00-0000-0000</span></a>
		</div>
		<div class="c-header__nav-global-wrapper">
			<!-- 内包される"nav-global"コンポーネント -->
			<nav class="c-nav-global"></nav>
		</div>
	</div>
</header>

エレメントの命名規則については次の理由から規定されています。

  • 単純な子孫セレクタでは、内包するコンポーネントへの影響をコントロールできない
  • 単純な子セレクタ・子孫セレクタでは、ライブラリなどで定義される外部のクラスのコンフリクトを完全に防げない
  • どのコンポーネントに帰属するか明瞭
  • エレメントの詳細度の差を小さくできる

内包したコンポーネントの子孫に、自分の子孫を定義してはいけません。

html
<!-- "header"コンポーネントの場合 -->
<header class="c-header">
	<div class="c-header__c-nav-global">
		<!-- 内包される"nav-global"コンポーネント -->
		<nav class="c-nav-global">
			<!-- ✅ 良い例: これは直属のコンポーネントのエレメントなので問題ない -->
			<ul class="c-nav-global__list">
				...
			</ul>

			<!-- ❌ 悪い例: 先祖にあるコンポーネントのエレメントはここには定義できない -->
			<div class="c-header__nav-element">...</div>
		</nav>
	</div>
</header>

1つの要素に複数のclassを定義してはいけません。コンポーネントを拡張したい場合は、完全に別のコンポーネントを作ってください。

html
<!-- ✅ 良い例 -->
<header class="c-header-specific">
	<!-- Elements... -->
</header>

<!-- ❌ 悪い例 -->
<header class="c-header c-header-specific">
	<!-- Elements... -->
</header>

👮‍♀️ 自動検知

このルールはMarkuplintによって警告されます。

コンポーネントとエレメントの状態管理

要素の状態(BEMでいうところのModifier)は、原則classを用いません。 次の優先順位で状態を管理します。

  1. 各HTML要素のもつ属性(disabled属性、required属性など)
  2. ARIA属性(aria-expandedaria-readonlyなど)
  3. data-*属性

例えば、disabled属性を有効にすれば、暗黙的にaria-disabledも有効になる性質があるので、関連する属性とARIA属性は二重定義しないようにしてください。

html
<!-- ✅ 良い例: ネイティブの属性があるものは属性で管理する -->
<button type="button" disabled>ボタン</button>

<!-- ❌ 悪い例: 属性で済むものをaria属性やdata属性に再定義したりする -->
<button type="button" aria-disabled="true" data-disabled="true">ボタン</button>

hidden属性の扱い

hidden属性とaria-hiddenの意味は異なるため、同じものとして扱ってはいけません。

aria-hidden属性は単純に支援技術に要素を隠すためのARIAステートです。しかしhidden属性は「現在のページの状態とその要素が関連性がまだない(将来は関連性が出てくる可能性がある)」もしくは「以前は関連性があったが現在はもう関連性がない」という意味を持つためです。値をuntil-foundとして自動展開可能な要素に対してはhidden属性を利用することはもちろんできますがaria-hiddenとはこれも性質が異なるため代替にはならないことに注意してください。

HTMLの属性にもWAI-ARIAにもどちらにもない状態を管理する場合(例えばスクロール位置でヘッダーの高さが変わる)などは、data-compact-modeのようなdata-*属性で定義します。

html
<!-- 通常は data-compact-mode が false -->
<header class="c-header" data-compact-mode="false"></header>
js
const header = document.querySelector('.c-header');
window.addEventListener('scroll', () => {
	// スクロール位置が100pxを超えたらコンパクトモードにする
	header.dataset.compactMode = window.scrollY > 100 ? 'true' : 'false';
});

❌ スタイルのみの目的に data-* 属性を利用する

data-*属性はあくまでもJavaScriptで状態を変化させるケースで扱います。スタイルのみの目的でdata-*属性を利用することは避けてください。

html
<!-- ❌ 悪い例 -->
<header class="c-header">
	<div data-header="inner">
		<div data-header="logo">サイト名</div>
	</div>
</header>

<!-- ✅ 良い例 -->
<header class="c-header">
	<div class="c-header__inner">
		<div class="c-header__logo">サイト名</div>
	</div>
</header>

粒度とコンポーネントの例

コンポーネントに分割する粒度はプロジェクトごとに異なりますが、以下の例を参考にしてください。なお、再利用できるかどうかは重要ではなく、コンポーネントが独立して完結すること、他のコンポーネントに影響を与えないことが重要です。

メインコンテンツコンポーネントのみ専用のルールがあるので、メインコンテンツのエレメントとヘルパークラスを参照してください。

コンポーネント名クラス名望ましい対象の HTML 要素備考
ページc-pagebody要素トップページ・下層ページでレイアウトなどが共通している場合。全体レイアウトのスタイルはここに定義する。
ページ(トップページ用)c-page-homebody要素トップページ限定。全体レイアウトのスタイルはここに定義する。
ページ(下層ページ用)c-page-subbody要素下層ページ全般。全体レイアウトのスタイルはここに定義する。
ヘッダーc-headerheader要素ページで一番外側にあるヘッダー要素。ロゴのリンクや、グロナビ以外の小さなリンク集を内包することもある。
フッターc-footerfooter要素ページで外側にあるフッター要素。サイトマップのようなリンクリストや組織情報などを内包することもある。
グローバルナビゲーションc-nav-globalnav要素サイトの全体を横断するリンクメニュー。
ローカルナビゲーションc-nav-local特になし自分のページの兄弟・下層のリンクメニュー。
メインコンテンツc-content-mainmain要素もしくはarticle要素を先祖にもつ要素ページの主要素。CMSで管理されるページや記事の本文にあたる部分が該当する。このコンポーネントのみ扱いが特殊になる。(👉メインコンテンツのエレメントとヘルパークラス
コンテンツインデックスc-content-indexmain要素を先祖にもつ要素各ページへの目次・リンク集となっているページで利用されるコンポーネント。CMSで管理されるブログ記事一覧やカテゴリーインデックス・タグインデックスなどで利用される。
パンくずリストc-nav-breadcrumbs特になしGoogle の推奨する構造化データを利用すること。形式は microdata(schema.org)が望ましい。HTML の構造上難しければ JSON-LD を利用すると良い。
ステップナビゲーションc-nav-steps特になし
ページネーションc-pagination特になし
メインビジュアルc-herosection
検索フォームc-search特になし

コンポーネント化すべきでないパーツや要素

再利用よりも他の要素への影響がないことを優先するために、次に挙げるパーツ・要素はコンポーネント化を避けてください。

  • ボタン単体
  • フォームコントロール要素(テキストフィールド・ラジオボタン・セレクトボックスなど)単体

コンポーネントごとに微妙なサイズ感やインタラクションがあることが多いのでコンポーネントとして独立は避け、コンポーネントのエレメントとして扱ってください。同じデザインでも再利用よりも他への影響がないことを優先してください

html
<header class="c-header">
	<button class="c-header__btn">ボタン</button>
</header>

<footer class="c-footer">
	<button class="c-footer__btn">ボタン</button>
</footer>

コンポーネント・エレメントの命名規則

クラス名は、ファイル名に関係するので機能から検索・サジェスト・ソートしやすいように、[機能名]-[修飾語・詳細]-[連番]という組み合わせで命名します。文法上は不自然かもしれませんが機能性を優先させます。[機能名]以外は任意です。それぞれの単語や形容詞はコーディング全般に関わる識別子の命名規則に準じてください(👉識別子の命名規則)。

機能名の例

  • page
  • header
  • footer
  • nav

修飾語・詳細が付いた例

  • nav-global
  • nav-local
  • nav-breadcrumbs
  • nav-steps
  • page-home
  • page-sub
  • page-contact

連番が付いた例

  • selection-01
  • selection-02

📖 メインコンテンツのエレメントとヘルパークラス

メインコンテンツ(content-mainコンポーネント)の内容はCMSなどで管理されるHTMLを含んだり、ページ独自のスタイルを扱うことが多いので例外的に専用のルールを設けます。

html
<div class="c-content-main">
	<!-- ❗この部分がメインコンテンツ専用のルール -->
</div>

エレメントのクラスの例外とクラス追加のルール

メインコンテンツのエレメントは基本的に自由です。ただし、クラス名はc-で開始しないでください。また、メインコンテンツの中にコンポーネントを内包してはいけません。

html
<div class="c-content-main">
	<!-- ✅ 良い例 -->
	<div class="foo">...</div>

	<!-- ❌ 悪い例 -->
	<div class="c-content-main__foo">...</div>

	<!-- ❌ 悪い例 -->
	<div class="c-foo">...</div>
</div>

🆔 id属性の利用

id属性はスタイルシートの目的では指定しないでください。

🤔 セマンティックとアクセシビリティ

各要素のコンテンツモデルを理解し、コンポーネントや機能、文脈によって最適なタグを選択してください。

WAI-ARIA

WAI-ARIAをHTMLに付加することで、HTMLでは不足している要素のセマンティックを補うことができます。しかし、WAI-ARIAが必要なケースは多くなく、HTML標準では再現できないコンポーネントを作成するときのみ使用してください。その場合、ARIA Authoring Practices Guide (APG)を参考にして、インタラクションの要件や振る舞いを推奨されているものに近い実装をするようにしてください。

  • 🙆 WAI-ARAIを使う必要があるケース
    • button要素がaria-pressedaria-expandedなどの状態をもつ必要がある場合
    • タブやカルーセルなどHTMLにないコンポーネントを扱う場合
  • 🙅 WAI-ARIAを使う必要がないケース
    • HTML標準にコンポーネントが存在する場合
    • Popoverなどで事済む場合

画像と代替テキスト

代替テキストはWCAGの達成基準 1.1.1 非テキストコンテンツを基準に考えてください。同等の目的が重要となるため、コーディングではなくデザインの段階で代替テキストが決まるように計画を立ててください。

alt属性が空の場合のロール

alt属性を空にすると、role="none"(またはrole="presentation")を付与したことと同じ効果が得られます。そのためalt属性が空の場合はrole="none"を付与する必要はありません。

html
<!-- ❌ role="none"は不要 -->
<img src="/path/to/file.png" alt="" role="none" />

img要素の性質を理解する

img要素の扱いでは次のことに注意してください。

画像の出し分け

display: noneの状態でも画像リソースのリクエストはされます( loading="lazy"になっている場合を除く)。そのため、レスポンシブデザインで画像を出し分ける場合は picture要素をつかってください。

html
<!-- ✅ 良い例 -->
<picture>
	<source srcset="/path/to/pict-some@xs.jpg" media="(max-width: 575px)" />
	<img src="/path/to/pict-some.png" alt="代替テキスト" />
</picture>

<!-- ❌ 悪い例 -->
<img class="sp-only" src="/path/to/pict-some@xs.png" alt="代替テキスト" />
<img class="pc-only" src="/path/to/pict-some.png" alt="代替テキスト" />

レイアウトシフトを発生させない

  • width属性とheight属性を指定して縦横比を明示しないといけないケース
    • 親要素に依存せず画像を成り行きで表示させる場合
    • 親要素によって幅は変わるが、高さが画像によって可変する場合
  • 明示しなくていいケース
    • CSS で widthheight を同時に指定している場合(ただし heightauto でない)
    • CSS で widthheight のどちらかを指定していて、且つ aspect-ratio を指定している場合
    • 幅と高さが親要素に完全に依存して、CSS の object-fit を使っている場合

自動付与

width属性とheight属性はビルド自動的に付与されるので、開発時に気にする必要はそんなにありません。ただし、ビルド時に画像のサイズが取得できない場合は手動で指定してください。

遅延デコード・遅延読み込みの設定

  • decoding属性はブラウザが適宜最適化しているため、指定しないでください
  • ファーストビュー以下のimg要素にはなるべくloading="lazy"を指定して、表示領域にない要素の自動ダウンロードを避けます

見出しとアウトライン

見出し要素のみでアウトラインを構成してもよいですし、セクショニング・コンテンツを利用してアウトラインを構成してもよいです。

html
<!-- ✅ 見出し要素のみでアウトラインを構成する -->
<h1>大見出し</h1>
<div>大見出しのコンテキスト</div>
<h2>中見出し</h2>
<div>中見出しのコンテキスト</div>
<h3>小見出し</h3>
<div>小見出しのコンテキスト</div>

<!-- ✅ セクショニング・コンテンツを利用した場合 -->
<h1>大見出し</h1>
<div>大見出しのコンテキスト</div>
<section>
	<h2>中見出し</h2>
	<div>中見出しのコンテキスト</div>
	<section>
		<h3>小見出し</h3>
		<div>小見出しのコンテキスト</div>
	</section>
</section>

見出しレベルの注意点

html
<!-- ❌ 廃止されたアウトラインアルゴリズムでランクを作る -->
<h1>大見出し</h1>
<div>大見出しのコンテキスト</div>
<section>
	<h1>中見出し</h1>
	<div>中見出しのコンテキスト</div>
	<section>
		<h1>小見出し</h1>
		<div>小見出しのコンテキスト</div>
	</section>
</section>

<!-- ❌ 見出しレベルのスキップ -->
<h1>大見出し</h1>
<div>大見出しのコンテキスト</div>
<section>
	<h6>中見出し</h6>
	<div>中見出しのコンテキスト</div>
	<section>
		<h4>小見出し</h4>
		<div>小見出しのコンテキスト</div>
	</section>
</section>

👮‍♀️ 自動検知

このルールはMarkuplintによって警告されます。

:::

ランドマーク

各コンポーネントの先祖となる要素にはランドマークを設けること。もしくはコンポーネントルート自体をランドマークをもつ要素でマークアップしてください。

html
<body>
	<header><!-- header は banner ランドマークをもつ --></header>
	<nav><!-- nav は navigation ランドマークをもつ --></nav>
	<main><!-- main は main ランドマークをもつ --></main>
	<footer><!-- footer は contentinfo ランドマークをもつ --></footer>
</body>
html
<body>
	<header><!-- ... --></header>
	<div class="c-hero">
		<!-- ❌ どのランドマークにも属していない -->
	</div>
	<nav><!-- ... --></nav>
	<main>
		<div class="c-hero">
			<!-- ✅ mainランドマークに内包されている -->
		</div>
	</main>
	<footer><!-- ... --></footer>
</body>

重複するランドマークロールの注意

ドキュメント内に複数のランドマーク要素がある場合、明示的にアクセシブルな名前を設定してください

html
<body>
	<header>
		<nav aria-label="メインメニュー"><!-- ... --></nav>
	</header>
	<main>
		<nav aria-label="ページ内メニュー"><!-- ... --></nav>
	</main>
	<footer>
		<nav aria-labelledby="sitemap">
			<h2 id="sitemap">ページ一覧</h2>
			<!-- ... -->
		</nav>
	</footer>
</body>

🤖 機械チェック可能

このルールはAxeによってチェック可能です。

p要素を濫用しない

p要素は段落を表しますが、他の要素で補えるテキストであればp要素を使う必要はありません。また、テキストや文字の代替画像でないかぎり画像単体をp要素で囲うのは不適切と言えます。縦に並べる要素がある場合はdiv要素を使ってください。

html
<!-- ❌ 悪い例 -->
<section>
	<h2>見出し</h2>
	<!-- 文章テキストの代替画像でなければ"段落"にする必要はない -->
	<p><img src="/path/to/file.png" alt="画像" /></p>
	<p>〜コンテキスト〜</p>
</section>

br要素の原則禁止

br要素はテキストを改行し、縦に方向に続きのテキストを送ることができますが、見た目の調整に使うことは避けてください。span要素でテキストを囲み、CSSのdisplayプロパティのinline-blockblockflexを活用してください。例外は詩・ポエムです。

html
<!-- ❌ 悪い例 -->
<p>こんにちは。<br class="sp-break" />さようなら。</p>

<!-- ✅ 良い例 -->
<p><span>こんにちは。</span><span>さようなら。</span></p>

👮‍♀️ 自動検知

このルールはMarkuplintによって警告されます。

Licensed under CC BY-NC-SA 4.0