コンテンツにスキップする

「プロの「引き出し」を増やす HTML+CSSコーディングの強化書」を読んだ

投稿時刻2023年11月10日 16:52

プロの「引き出し」を増やす HTML+CSSコーディングの強化書」を 2,023 年 11 月 10 日に読んだ。

目次

メモ

背景全幅+コンテンツ幅固定のパターン p116

section._bg {
	/* 全幅背景 */
	margin-left: calc(50% - 50vw);
	margin-right: calc (50% - 50vw);
	padding-left: calc(50vw - 50%);
	padding-right: calc(50vw - 50%);
	background: #cdecf0;
}

margin: 0 calc(50% - 50vw) と書いただけでは、コンテンツの中身も幅いっぱいまで広がってしまいます。
今回のようにコンテンツの中身はコンテナ幅に揃える必要がある場合には、左右の padding を calc (50vw - 50%) としておきましょう。
こちらは calc() の中の計算値が margin とは逆になります。
こちらも分かりやすいように左側だけで考えると、まず padding-left: 50vw で画面の半分の余白を確保し、
そこから padding-left: -50% とすることで親要素の半分だけ padding を削るという調整をしています。
これを右側も同様に行うことで、親要素と同じ幅のコンテンツ領域を残して左右の領域を padding で画面の端まで埋めています。

この手法は非常に便利ですが、 vw を使うためどうしてもスクロールバーの幅の分だけコンテンツの幅との間に差分が生じ、それが原因で左右にスクロールバーが出てしまうという問題があります。
これを解決するには、親要素のどこかで overflow: hidden を入れる必要があります。
筆者は html 要素と body 要素の両方に overflow-x: hidden; (※ウィンドウ全体にかかわるので横方向のみ) を指定することで解決しています。

margin-top か margin-bottom か p258

margin の相殺を避けるためにどちらか一方で統一するとして、どちらに統一するのが良いのでしょうか?
これは昔から意見が分かれる点ですが、「上から順番に書いていくので margin は下に付けたほうが自然」という理由から margin-bottom で統一する人のほうが若干多いような印象です。
筆者も以前は margin-bottom で統一していました。

ただ、近年は margin-top で統一するように変えています。
その理由は、「要素同士の余白は新たに要素が下に追加された時に発生するものであり、その余白は追加されたほうの要素に由来するのだから margin-top で付けたほうが自然ではないか?」と考えるようになったためです。

正直このあたりは個人の感覚によるところもありますのでどちらが正しいというものではありません。
ただ、後から追加される要素の margin-top に余白を付けるルールにしておくと、不要な要素間の余白調整があまり必要にならないことが多いと感じます。

また、margin-bottom で統一した場合、必ず一番最後の要素の下マージンを何らかの方法で処理しなければなりません。
同じことは margin-top で統一した場合でも発生しますが、
末尾の要素は常に不確定であるのに対し先頭の要素はなくなることはありません。
不確定要素が少ない分だけ考えることも少なくて済むため、僅かな差ではありますが、個人的には margin-top のほうがシンプルに作れるように思います。

セクション内の先頭・末尾の要素の余白調整 p264

各セクションごとに上下に padding で余白が設定されることを前提とする場合、
セクション内コンテンツの先頭要素と末尾要素に付いている margin が相殺されずに邪魔になることが想定されます。
不要となる margin だけユーティリティ class で打ち消すこともできますが、それではコンポーネントの流用性に支障が出てあまり好ましくないので、以下のような形で自動的に打ち消されるようにしておきましょう。
セクション内の最後の要素の margin-bottom を 0 に
.section >:last-child { margin-bottom: 0; }
対象を子セレクタで絞っておかないと、孫要素以下の :last-child にも影響が出てしまうので注意してください。
また、要素間の margin を margin-top としている場合はセクション末尾の margin 処理は不要です。
コンテンツに対して margin-bottom で統一して余白を付けている場合、セクション内の末尾の要素の margin-bottom は必ず 0 としなければなりません。
「末尾の要素」は :last-child 、「セクション直下の子要素」は子セレクタ (>) で指定できるので、
上記のように指定しておくことでどんなものが来たとしても自動的に末尾の要素の margin-bottom を 0 にしておくことができます。
セクション内の最初の要素の margin-top を 0 に
section >:first-child { margin-top: 0; }
同様に、セクション内の最初の要素の margin-top も不要なはずですので、こちらは :first-child で margin-top を 0 にしておくこともできます。
ただし、 margin-bottom で統一している場合には先頭の要素に上マージンが付くことはありませんので、
こちらは margin-top で統一しており、かつセクション先頭に配置された要素に万が一 margin-top が付いていた場合に、それを無効化するための措置となります。
複雑なレイアウトの場合、セクションの先頭に来る要素に敢えて margin (ネガティブマージン含む) を取る必要が出てくることも考えられるので、
先頭要素の margin-top に関しては敢えて処理せず、必要な場合にのみユーティリティで打ち消しを入れる方法も考えられます。

見出しレベルと文書のアウトライン p283

コンテンツ部分のセマンティックなマークアップにおいて、最低限しっかり意識する必要があるのは、文書の見出しレベルを正しく保つことです。
ご存知の通り HTML には h1 ~ h6 までの 6 段階の見出しレベルが用意されているので、 h1 から順番に、情報の階層構造を意識しながら階層レベルに応じて h2 、 h3 、 h4 ……と見出し要素をマークアップしていきます。

各種ブラウザは見出しのレベルを頼りにして文書のアウトラインを構築します。
アウトラインとは、その文書の骨格のようなものであり、機械的に内容を整理・解釈する上で重要な情報構造、屋台骨にあたります。
アクセシビリティの面においても、見出しを適切に設定していると、スクリーンリーダの見出しジャンプ機能を使って素早く必要な情報にアクセスできるようになります。

見出し要素はHTMLの中でも基本中の基本ですが、マークアップにおいてはあらゆる方面でHTMLの品質を担保する最重要項目です。
自分のマークアップによってどのようなアウトラインが構築されているのかは、 HTML5 Outliner や W3C の Markup Validation Service などのツールで確認できますので、制作工程の早い段階で少なくとも一度はアウトラインがどうなっているのか確認するようにしましょう。

參考
HTML5 Outliner (https://gsnedders.html5.org/outliner/)
W3C Markup Validation Service (https://validator.w3.org/)

セクションと文書の全体構造 p284

次に意識したいのが文書全体のセクションと全体構造です。
これを意味付けするのは section ・ article ・ nav ・ aside の 4 つのセクション要素と、 header ・ footer ・main の 3 つの構造化要素です。
これらも HTML5 のマークアップを学んだ方であれば基本中の基本として日常的に使用しているものであると思いますが、見出し要素と共により明確に文書全体の構造と各エリアの役割をコンピュータに伝えるものとして、今一度その役割を見直しておきましょう。
header-footer-main
Webページは文書の純粋なコンテンツ部分と、サイト全体の共通情報を格納するヘッダー領域・フッター領域に大きく分かれています。
ほぼ定型フォーマットとも言えるこの大きな役割の違いについては、特別な事情がなければコンテンツ部分をmain要素、ヘッダー領域をheader要素、フッター鎮域をfooter要素としてマークアップしておけば良いでしょう。
なお、main要素は多くのスクリーンリーダーで本文先頭に移動する際の目印の1つとして利用されます。
特別にスキップリンク機能などを用意しなくても適切に main 要素の範囲を設定しておけば支援技術を必要とするユーザーに対しても素早くコンテンツ本文へアクセスする手段を提供できます。
section-article-aside-nav
見出しがあればブラウザ側は文書のアウトラインを構築できますが、セクション要素を使うことで見出しとそれに伴うコンテンツのかたまりである「セクション」に対して、より詳しい役割の違いを明示できます。
セクション要素の使用は必須ではありませんが、可能な限り見出しとともにセクション要素を使ってそのセクションの範囲と役割を明確化することが推奨されています。
また、特に nav 要素については、多くのスクリーンリーダーに対して「ナビゲーションである」という情報を明示してユーザーに伝えることができるため、グローバルナビなどの主要なナビゲーションエリアについては nav 要素を使うことを推奨します。

英単語は小文字で記述する p291

<!-- NG 例 -->
<h2 class="heading">SAMPLE</h2> // 大文字で記述している。

<!-- OK 例 -->
<h2 class="heading">Sample</h2>
.heading { text-transform: uppercase; }

もうひとつよくあるケースで問題になるのが、デザイン的に英単語を全て大文字で見せたい場合です。
全て大文字で「SAMPLE」と記述してしまうと、スクリーンリーダーの中には「サンプル」ではなく「エス・エー・エム・ピ・エル・イー」といった具合にアルファベットを単体で読み上げてしまうものがあります。
確実に英単語として読ませる必要がある場合には、「sample」または「Sample」のように、 2文字目以降は小文字で記述する必要があります。
英単語を大文字で見せたい場合には念のため CSS で text-transform: uppercase; を指定するようにしておきましょう。

装飾的な画像の alt は空にする p292

<!-- NG例 (alt属性なし) -->
<a href="#" class="btn">
	<img src="img/icon_mail.png" class="btn__icon">お問い合わせ // altがない
</a>

<!-- OK例 (alt属性の値が空) -->
<a href="#" class="btn">
	<img src="img/icon_mail.png" class="btn_icon" alt="">お問い合わせ
</a>

装飾パーツやイメージ画像、同内容のテキストを伴うアイコンなど、視覚的な効果のみを意図したもので情報として伝達する必要のない画像については、 alt="" のように alt属性の値を空にしておきましょう。
alt 情報が不要だからといって alt 属性そのものを削除してしまうのはNGです。
スクリーンリーダーの中にはファイル名をそのまま読み上げてしまうものがあり、情報の読み取りに支障が出る恐れがあるからです。

図解・グラフ p295

<figure class="graph">
	<figcaption class="graph__title">「けりぐるみ」 満足度調査</figcaption>
		<img src="img/graph.png" alt="円グラフ とても満足 35% 、満足 57% 、どちらともえない 6% 、不満 2% 。とても満足・満足合わせて 92% のお客様が満足と答えました。" width="718" height="542">
		<p class="graph__note">当社「けりぐるみ」 お買い上げのお客様268人のアンケート調査 (2021年4月現在)</p>
</figure>

図解やグラフなどを掲載する場合はaltの内容に注意が必要です。
図解やグラフはそれ自体が重要なコンテンツですので、画像が表示されなくてもその図解やグラフで伝えたい情報が伝わるようにする必要があります。
そうしなければスクリーンリーダーのユーザーには何の情報も伝わらないからです。
前後に図解やグラフの内容を解説したテキストがなく、画像だけで情報を伝達している場合はaltにその画像で伝えたい情報をきちんとテキストに書き起こして記述する必要があります。
内容によってはかなり長い文章で説明する必要が出てくると思われますが、それがなければスクリーンリーダーに対して情報を伝達する手段がないのですから仕方ありません。
この場合、その図解・グラフが何を伝えたいのか正確に把握し、適切な表現で文章を書く必要があることから、可能であればライターやディレクターに「テキスト原稿」として依頼をしたほうが良いでしょう。
なお、前後にその図解やグラフの内容を解説する本文テキストがある場合は、内容の重複を避けるため、 alt の中身は alt="○○のグラフ" などの簡単な説明だけで十分です。

人物・動物・風景・その他のコンテンツ画像 p296

<section class="media">
	<div class="media__body">
		<h2 class="media__title">パソコン前が定位置</h2>
		<p class="media__txt">リモートワークが増えた昨今。家でネコさんを愛でながら仕事できるなんて最高!…と思っている人も多いかも知れませんが、実際の現場はこうです。キーボード打てません。</p>
	</div>

	<figure class="media__photo">
		<img src="img/ph_cat01.jpg" alt="パソコンのモニタ前にでーんと寝そべってこちらを見つめる白猫の写真。キーボードは猫の体の下にあります。仕事できません。" width="640" height="480">
	</figure>
</section>

おそらくaltの中で最も難しいのが、記事中に挿入される人物・動物・風景その他の一般的な写真コンテンツでしょう。
このような写真類はイメージ画像ではなくコンテンツの一部ですので、 alt を空にするわけにはいきません。
かといって機械的にaltの中身を決めることもできず、正確に記述するには国語力・文章作成力が求められます。

tabindex 属性 p299

<!-- tabindex なし -->
<a href="#" class="btn">a 要素</a>
<button class="btn">button 要素</button>
<div class="btn">div 要素</div> // フォーカスが当たらない

<!-- div 要素に tabindex="0" -->
<a href="#" class="btn">a 要素</a>
<button class="btn">button 要素</button>
<div class="btn" tabindex= "0">div 要素</div> // フォーカスが当たる

JavaScript で動的な UI を作る際、開発者都合でどうしても div や span など、標準ではフォーカスされない静的要素に対してキーボード操作を可能にする必要に迫られることもあります。
この場合は tabindex 属性でキーボードフォーカス可能な状態にしなければなりません。
フォーカスが当たらなければキーボードでは全く操作ができなくなるからです。
具体的にはフォーカスが当たるようにしたい静的要素に tabindex="0" と指定します。
こうすることで、HTMLソースコードの出現順に Tab キーでフォーカスが当たるようになります。

逆にもともと自動でフォーカスがあたる要素をフォーカス対象から除外する目的で使用するのが tabindex="-1" などの "負の整数" の値です。
こちらはフォーカス制御を別途 JavaScript で実装することを前提とした機能となります。

もう 1 つ、 tabindex では "正の整数" を指定することでフォーカス順序を任意で変更できるという機能もあります。
しかしこれを使う場合はページ内の全てのフォーカス可能な要素に対して明示的なフォーカス制御が必要になるので、よほどのことがない限りおすすめはできません。

WAI-ARIAとは p301

WAI-ARIA (Web Accessibility Initiative Accessible Rich Internet Applications | ウェイ・アリア) とは、 W3C が定めたアクセシビリティのための追加仕様で、 HTML だけでは表現しきれない構造や役割、状態などを明示できるようにするためのものです。

WAI-ARIA の仕様は大きく分けると役割を定義する role 属性と、 性質・状態を定義する aria-* 属性の2つに分類されます。
aria-* 属性は更に性質を現すプロパティと状態を表すステートに分類されます。
これらを適切にマークアップに盛り込んでおくことで、スクリーンリーダーを利用する方がWebサイト・Webアプリケーションを操作する際の手助けとなります。

ランドマークロール p303

初めて WAI-ARIA を導入する時には、まずはランドマークロールから始めるのが良いと思います。
ランドマークロールはページ全体のレイアウトを定義するためのロールで、種類も少なく、その多くに暗黙のロールを持つHTML要素が存在するので、理解しやすいからです。
また、これはスクリーンリーダーがページ内を移動する時の目印となるものであり、基本的に設定するだけで要素をアクセシブルにすることができるため、導入の敷居が低いわりに効果が分かりやすいのもポイントです。

ランドマークロールの一覧とその用途は以下の通りです。

ランドマークロール一覧
ロール名 意味 対応する HTML
banner ページのヘッダー (ページ内に1つ) セクション要素の子孫でない header
contentinfo ページのフッター領域(ページ内に1つ) セクション要素の子孫でない footer
main メインコンテンツ領域(ページ内に1つ) main 要素
complementary 補足のコンテンツ (サイドバーなど) aside 要素
navigation ナビゲーション nav 要素
region 汎用的なランドマーク section 要素 
search 検索フォーム -
form フォーム form 要素

search 以外のランドマークロールは全て暗黙のロールを持つ HTML 要素が存在します。
基本的にHTML要素が同等の暗黙のロールを持つ場合は、重複してrole属性を記述する必要はありません。
何らかの事情で各領域をdiv要素などで代用しなければならない場合に使用するものと覚えておきましょう。

使用頻度が高いと思われるその他のロール p306

他にもロール属性は非常に沢山あり、その全てを理解して使いこなすのはなかなか骨が折れます。
しかし暗黙のロールと同じ意味の role 属性はそもそも明示的に付与する必要もないので、まずはWebサイトでよく使うインターフェースでありながら、HTML自体にそれを意味付けする要素が存在しないものを優先的に覚えていくのが合理的でしょう。
積極的に使用することでアクセシビリティを高める効果が高いと思われるものをいくつか表にまとめましたので、まずはこうしたものから使ってみると良いのではないでしょうか。

名詞
よく使われる場所
tablist タブ要素をまとめたリスト タブ切り替え
tab タブ要素 タブ切り替え
tabpanel タブパネル要素 タブ切り替え
dialog ブラウザ内ウィンドウ ポップアップ・モーダルウィンドウ・動画プレイヤーなど
presentation/none WAI-ARIAの構造から隠す スクリーンリーダーに読ませる必要のない要素 (アイコンなど)

他にどのような role があるかは、 各自必要に応じて仕様書などで確認してください。
なお一般的なWebサイトではなく、ユーザー操作が主体のWebアプリケーションを開発している場合は特にWAI-ARIAの仕様全体の把握が必要になると思われますので注意してください。

参考:
WAI-ARIA 1.1 role 属性の定義
5.4 Definition of Roles
https://www.w3.org/TR/wai-aria-11/#role_definitions

実装事例 2 アイコン p314

アイコンには
・同義のテキストを伴い、それ自体は装飾的な役割しか持たないもの
・アイコン単体で特定の機能・役割を表現しているもの
の2種類があります。
いずれの場合もアイコン自体がimg画像でHTMLに埋め込まれているのであればalt属性を適切に設定すればアクセシブルにすることは可能です。
しかし、アイコンフォントや擬似要素などを使って視覚的にはアイコンの絵柄が表示されていても、HTMLソース的には実態がないものについては、WAI-ARIAで補足することがアクセシビリティ的には望ましいと言えます。
以下に3パターンのアイコンの実装例を紹介します。
aria-hidden で隠す
<!-- アイコン付きのリンク -->
<a href="/contact/">
	<i class="fas fa-envelope" aria-hidden="true"></i>お問い合わせ
</a>

このサンプルの場合、「お問い合わせ」というテキスト情報が存在しますので、アイコン自体はスクリーンリーダーにとって不要な情報です。
このような場合は、 aria-hidden="true" でスクリーンリーダーに対して非表示 (認識されない状態) とするのが適切です。
aria-labelでラベル付けする
<!-- アイコンのみで表現されたリンク -->
<a href="/contact/" class="mark" aria-label="お問い合わせ">
	<i class="fas fa-envelope" aria-hidden="true"></i>
</a>

アイコン単体で特定の意味や役割を表現するインフォグラフィックスとしてアイコンフォントが使われている場合は、
このようにaria-labelでラベル付けをしておけば、アイコンにフォーカスが当たると「お問い合わせ」と読み上げてくれます。
i 要素に aria-label を設定する際の注意
i 要素自体にaria-labelを設定するのが本来の形と思われますが、Safari ・ iOS Safari + VoiceOver の環境では要素に設定しないとうまく読み上げられないため、このケースではa要素のほうにラベルを設定しています。
スクリーンリーダー用のテキストを使う
<!-- アイコンのみで表現されたリンク -->
<a href="/contact/">
	<i class="fas fa-envelope" aria-hidden="true"></i>
	<span class="visually-hidden">お問い合わせ</span>
</a>

/* ビジュアルブラウザからは隠し、スクリーンリーダーには読ませる */
.visually-hidden {
	position: absolute;
	white-space: nowrap;
	width: 1px;
	height: 1px;
	overflow: hidden;
	border: 0;
	padding: 0;
	clip: rect(0 0 0 0);
	clip-path: inset (50%);
	margin: -1px;
}

aria-labelを設定する代わりに、HTML上にスクリーンリーダー向けのテキストを用意しておき、ビジュアルブラウザからは非表示にしつつ、スクリーンリーダーからは読めるようにしておくという方法もあります。
これは一般的に「visually-hidden」と呼ばれる手法で、アイコンに限らずいわゆる「隠しテキスト」を実装するための手法です。

サンプルではアイコンの意味付けとして使っていますが、例えば「セマンティクス的には h2 や h3 などの見出しが必要でもビジュアル的にはそれを見せたくない」といったケースでも使用できるため、広い範囲に応用が可能です。
スクリーンリーダー対策としてはaria-labelを使った手法と差はありませんが、HTML上に記載されたテキストが検索エンジンにもインデックスされるため、アクセシビリティとSEOの対策を共通化する目的がある場合はこちらがおすすめです。

p330

スクリーンリーダーで読み上げをする場合、 Mac ユーザーは Voice Over + Safari、 Windows ユーザーは NVDA + Chrome/Firefox を推奨します。
(Windows ユーザーで PC-Talker を試したい場合は無料のクリエイター版をインストールすると良いでしょう)
参考文献

WAI-ARIA 1.7
https://www.w3.org/TR/2017/REC-wai-aria-1.1-20171214/

WAI-ARIA 1.1 日本語訳
https://momdo.github.io/wai-aria-1.1/

WAI-ARIA の基本
https://developer.mozilla.org/ja/docs/Learn/Accessibility/WAI-ARIA_basics

WAI-ARIA オーサリング プラクティス 1.1
https://waic.jp/docs/2019/NOTE-wai-aria-practices-1.1-20190207/

DIGITAL A11Y
https://www.digitala11y.com/

エー イレブン ワン [WebA11y.jp]
https://weba11y.jp/

基本的なフォームのヒント
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/forms/Basic_form_hints 

はじめてみよう!お問い合わせフォームのウェブアクセシビリティ対応の方法
https://ics.media/entry/201016/