ポートフォリオサイトのアクセシビリティ対応完全ガイド|スクリーンリーダー・キーボード操作・コントラスト比を一から実装する


はじめに

前回の記事では無料デザインツールをCanva・デザインAC・Convertio・ファビコン作成まで場面別にまとめて紹介しました。今回はポートフォリオサイトのアクセシビリティ対応を解説します。アクセシビリティとはすべてのユーザーがサイトを使いやすい状態にすることです。視覚障害のある方が使うスクリーンリーダーへの対応・マウスを使わないキーボード操作のサポート・色のコントラスト比の確保まで、基本的な考え方と具体的な実装方法を一から解説します。


1. アクセシビリティとは

1.1 Webアクセシビリティの基本概念

Webアクセシビリティとは障害のある方も含めてすべてのユーザーがWebサイトを利用できる状態を指します。対象となるユーザーは視覚障害者だけではありません。

ユーザーの状況アクセシビリティが必要な理由
視覚障害スクリーンリーダーでサイトを読み上げる
色覚特性特定の色の組み合わせが区別しにくい
運動障害マウス操作が困難でキーボードのみを使う
高齢者小さなテキストや複雑なUIが使いにくい
一時的な障害腕の骨折中・強い日差しでスマートフォン画面が見えにくいなど

1.2 WCAGとは

**WCAG(Web Content Accessibility Guidelines)**はW3Cが策定したWebアクセシビリティの国際標準ガイドラインです。以下の4つの原則に基づいています。

原則内容
知覚可能(Perceivable)情報をすべての感覚で受け取れる
操作可能(Operable)キーボードのみでも操作できる
理解可能(Understandable)内容・操作方法が理解できる
堅牢(Robust)支援技術(スクリーンリーダーなど)で正しく解釈できる

WCAGにはA・AA・AAAの3段階の適合レベルがあります。一般的なWebサイトではレベルAAの達成を目標にします。

💡 アクセシビリティ対応はポートフォリオサイトの差別化になります: エンジニアとしてアクセシビリティを意識したコードが書けることは採用担当者に良い印象を与えます。意識して取り組んでいることをポートフォリオの説明文に加えるのもおすすめです。


2. セマンティックなHTMLを書く

2.1 セマンティックHTMLとは

セマンティックHTMLとは意味のあるHTMLタグを適切な場所に使うことです。スクリーンリーダーはHTMLのタグの意味を読み取ってユーザーに伝えます。すべてを <div> で作るのではなく、目的に合ったタグを使うことがアクセシビリティの第一歩です。

<!-- ❌ セマンティックでない書き方 -->
<div class="header">
    <div class="nav">
        <div class="nav-item"><a href="/">Home</a></div>
    </div>
</div>
<div class="main">
    <div class="article">
        <div class="title">記事タイトル</div>
        <div class="content">本文...</div>
    </div>
</div>
<div class="footer">フッター</div>

<!-- ✅ セマンティックな書き方 -->
<header>
    <nav>
        <ul>
            <li><a href="/">Home</a></li>
        </ul>
    </nav>
</header>
<main>
    <article>
        <h1>記事タイトル</h1>
        <p>本文...</p>
    </article>
</main>
<footer>フッター</footer>

2.2 よく使うセマンティックタグ

タグ役割
<header>サイトまたはセクションのヘッダー
<nav>ナビゲーションメニュー
<main>ページの主要コンテンツ(1ページに1つ)
<article>独立したコンテンツ(記事・投稿・制作実績など)
<section>関連するコンテンツのグループ
<aside>サイドバー・補足情報
<footer>サイトまたはセクションのフッター
<figure>画像・図表などのコンテンツ
<figcaption><figure> のキャプション

2.3 見出しの階層を正しく設定する

<h1> から <h6> の見出しは階層を守って使います。スクリーンリーダーは見出しを目次として使うため、順序をスキップすることは避けましょう。

<!-- ❌ 階層をスキップしている -->
<h1>ポートフォリオサイト</h1>
<h3>About</h3>  <!-- h2をスキップしている -->

<!-- ✅ 階層を守っている -->
<h1>山田太郎のポートフォリオ</h1>
    <h2>About</h2>
        <h3>スキルセット</h3>
        <h3>経歴</h3>
    <h2>Works</h2>
        <h3>制作実績01</h3>
        <h3>制作実績02</h3>
    <h2>Contact</h2>

⚠️ <h1> は1ページに1つだけにしましょう: 複数の <h1> があると検索エンジンとスクリーンリーダーの両方でページ構造の把握が難しくなります。


3. 画像のalt属性を正しく設定する

3.1 alt属性の重要性

画像の alt 属性はスクリーンリーダーがユーザーに画像の内容を伝えるために使います。また、画像が読み込めなかった場合の代替テキストとしても機能します。

3.2 alt属性の書き方

<!-- ✅ 内容を説明する画像 -->
<img src="profile.jpg" alt="山田太郎のプロフィール写真。白いシャツを着てパソコンの前に座っている">

<!-- ✅ 制作実績の画像 -->
<img src="works-01.jpg" alt="○○株式会社のコーポレートサイト。白を基調としたシンプルなデザイン">

<!-- ✅ 装飾目的の画像(空のaltを設定してスクリーンリーダーが読み飛ばすようにする) -->
<img src="decoration.png" alt="">

<!-- ❌ ファイル名をそのまま入れている -->
<img src="profile.jpg" alt="profile.jpg">

<!-- ❌ altを省略している -->
<img src="works-01.jpg">
画像の種類altの書き方
情報を持つ画像画像の内容を簡潔に説明する
リンクの中にある画像リンク先の内容を説明する
装飾目的の画像alt="" と空にする
グラフ・図表データの内容を文章で説明する

4. キーボード操作をサポートする

4.1 フォーカスの可視化

マウスを使わずにキーボードのTabキーでフォーカスを移動するユーザーのために、フォーカスが当たっている要素を視覚的に示すことが重要です。

/* ❌ フォーカスを非表示にしてはいけない */
*:focus {
    outline: none;  /* これは禁止 */
}

/* ✅ デフォルトのフォーカスを上書きする場合は必ず代替スタイルを設定する */
*:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(26, 95, 192, 0.5);  /* カスタムフォーカスリング */
}

/* ✅ キーボード操作のみフォーカスを表示する(マウスでは非表示) */
*:focus-visible {
    outline: 2px solid #1A5FC0;
    outline-offset: 3px;
    border-radius: 3px;
}

💡 :focus-visible を使うのがモダンなアプローチです: マウスでクリックした場合はフォーカスリングを表示せず、キーボード操作のときだけ表示します。UXとアクセシビリティの両立ができます。

4.2 Tabキーの操作順序を管理する

<!-- tabindex="0":通常のTab順序に追加する -->
<div tabindex="0" role="button" class="custom-btn">
    カスタムボタン
</div>

<!-- tabindex="-1":Tab順序から除外してJavaScriptからのみフォーカス可能にする -->
<div tabindex="-1" id="modal-content">
    モーダルのコンテンツ
</div>

<!-- tabindex="1以上":Tab順序を明示的に指定(非推奨・通常は使わない) -->

⚠️ tabindex に正の値を使うのは非推奨です: 正の値(tabindex="1" など)はTab順序を不規則にするため混乱を招きます。HTMLの文書順序でTab順序が決まるように構造を工夫しましょう。

4.3 ハンバーガーメニューをキーボード対応にする

前回の記事で実装したハンバーガーメニューにキーボード対応を追加します。

<button
    class="hamburger"
    id="hamburger"
    aria-expanded="false"
    aria-controls="nav"
    aria-label="メニューを開く"
>
    <span aria-hidden="true"></span>
    <span aria-hidden="true"></span>
    <span aria-hidden="true"></span>
</button>

<nav id="nav" class="nav">
    <!-- ナビゲーション -->
</nav>
const hamburger = document.getElementById('hamburger');
const nav       = document.getElementById('nav');

hamburger.addEventListener('click', () => {
    const isOpen = nav.classList.toggle('is-open');

    // aria-expandedを更新してスクリーンリーダーに状態を伝える
    hamburger.setAttribute( 'aria-expanded', isOpen );
    hamburger.setAttribute( 'aria-label', isOpen ? 'メニューを閉じる' : 'メニューを開く' );
});

// Escapeキーでメニューを閉じる
document.addEventListener('keydown', ( e ) => {
    if ( e.key === 'Escape' && nav.classList.contains('is-open') ) {
        nav.classList.remove('is-open');
        hamburger.setAttribute('aria-expanded', 'false');
        hamburger.setAttribute('aria-label', 'メニューを開く');
        hamburger.focus();  // フォーカスをボタンに戻す
    }
});

4.4 スキップリンクを設置する

スキップリンクとはキーボードユーザーがナビゲーションを飛ばして本文に直接移動できるリンクです。Tabキーを押すと画面の上部に表示されます。

<body>
    <!-- スキップリンク(初期状態は画面外に隠す) -->
    <a href="#main-content" class="skip-link">本文へスキップ</a>

    <header>
        <nav><!-- ナビゲーション --></nav>
    </header>

    <main id="main-content">
        <!-- メインコンテンツ -->
    </main>
</body>
/* スキップリンク:通常は画面外に配置してフォーカス時だけ表示 */
.skip-link {
    position: absolute;
    top: -100px;
    left: 16px;
    padding: 8px 16px;
    background: #1A5FC0;
    color: white;
    border-radius: 0 0 6px 6px;
    font-weight: 600;
    text-decoration: none;
    transition: top 0.2s ease;
    z-index: 9999;
}

.skip-link:focus {
    top: 0;  /* フォーカス時に画面内に表示 */
}

5. ARIAを使ってスクリーンリーダーに情報を伝える

5.1 ARIAとは

**ARIA(Accessible Rich Internet Applications)**はHTMLだけでは伝えられない役割・状態・プロパティをスクリーンリーダーに伝えるための属性セットです。

原則:HTMLのセマンティクスで表現できる場合はARIAを使わない。 <button> を使えば role="button" は不要です。ARIAは本当に必要な場面だけに使います。

5.2 よく使うARIA属性

<!-- aria-label:要素のラベルを明示的に指定する -->
<button aria-label="検索を実行">🔍</button>

<!-- aria-hidden:スクリーンリーダーから隠す(装飾アイコンなど) -->
<span aria-hidden="true">✨</span>装飾テキスト

<!-- aria-expanded:折りたたみ要素の開閉状態を伝える -->
<button aria-expanded="false" aria-controls="menu">メニュー</button>

<!-- aria-current:現在のページを示す(ナビゲーションで使用) -->
<nav>
    <a href="/" aria-current="page">Home</a>
    <a href="/works">Works</a>
</nav>

<!-- aria-live:動的に変化するコンテンツをスクリーンリーダーに読み上げさせる -->
<div aria-live="polite" id="status-message">
    <!-- JavaScriptで変更されるメッセージ -->
</div>

<!-- aria-describedby:関連する説明要素を指定する -->
<input type="email" aria-describedby="email-hint">
<p id="email-hint">example@email.comの形式で入力してください。</p>

5.3 フォームのアクセシビリティ

前回の記事で作ったお問い合わせフォームにARIAを追加します。

<div class="form-group">
    <label for="name">
        お名前
        <span class="required" aria-label="必須">必須</span>
    </label>
    <input
        type="text"
        id="name"
        name="name"
        autocomplete="name"
        aria-required="true"
        aria-describedby="name-error"
    >
    <p
        class="error-message"
        id="name-error"
        role="alert"
        aria-live="polite"
    ></p>
</div>
// エラーメッセージをaria-invalidで伝える
function showError( inputEl, errorEl, message ) {
    inputEl.classList.add( 'is-error' );
    inputEl.setAttribute( 'aria-invalid', 'true' );  // 追加
    errorEl.textContent = message;
}

function showValid( inputEl, errorEl ) {
    inputEl.classList.remove( 'is-error' );
    inputEl.removeAttribute( 'aria-invalid' );  // 追加
    errorEl.textContent = '';
}

6. 色のコントラスト比を確保する

6.1 コントラスト比の基準

前回のデザイン原則の記事でも触れましたが、改めてアクセシビリティの観点から整理します。

テキストの種類WCAG AA基準WCAG AAA基準
通常テキスト(18px未満)4.5:1以上7:1以上
大きなテキスト(18px以上または14px以上の太字)3:1以上4.5:1以上
UI要素・グラフィック3:1以上

6.2 よくある配色の問題と解決策

/* ❌ コントラスト比が低い(灰色のテキストに注意) */
.text-muted {
    color: #aaaaaa;    /* 白背景との比率:2.32:1(不十分) */
    background: #fff;
}

/* ✅ コントラスト比を確保した灰色 */
.text-muted {
    color: #767676;    /* 白背景との比率:4.54:1(AA基準を満たす) */
    background: #fff;
}

/* ❌ 赤と緑の組み合わせ(色覚特性の方が区別しにくい) */
.status-success { color: #00aa00; }
.status-error   { color: #aa0000; }

/* ✅ 色だけでなくアイコンやテキストでも状態を伝える */
.status-success::before { content: '✓ '; }  /* アイコンを追加 */
.status-error::before   { content: '✕ '; }
.status-success { color: #1D7A44; }
.status-error   { color: #A01010; }

6.3 コントラスト比の確認ツール

ツールURL使い方
WebAIM Contrast Checkerwebaim.org/resources/contrastchecker前景色と背景色を入力して比率を確認
Chrome DevToolsF12 → Elements → StylesCSS変数をホバーするとコントラスト比が表示される
Colour Contrast Analyserdeveloper.paciellogroup.comデスクトップアプリ。画面上の任意の色を計測できる

7. 動きとアニメーションへの配慮

前回のアニメーション記事でも触れた prefers-reduced-motion を改めて確認します。

/* 標準:アニメーションあり */
.fade-in {
    transition: opacity 0.7s ease, transform 0.7s ease;
}

/* OSの「アニメーションを減らす」設定をしているユーザーへの対応 */
@media (prefers-reduced-motion: reduce) {
    .fade-in {
        transition: none;
    }

    /* すべてのアニメーションを一括で無効化する場合 */
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

8. アクセシビリティを検証する

8.1 自動検査ツール

ツール種類使い方
LighthouseChrome DevTools内蔵F12 → Lighthouse → アクセシビリティを計測
axe DevToolsChrome拡張機能ブラウザ上でアクセシビリティの問題を自動検出
WAVEwave.webaim.orgURLを入力するとビジュアルで問題箇所を表示

💡 Lighthouseのアクセシビリティスコアは100点を目指しましょう: Lighthouseは自動検出できる問題を100点満点でスコア化します。ただし自動検査では検出できない問題もあるため、スコアが100点でも完全ではありません。

8.2 スクリーンリーダーで実際に確認する

スクリーンリーダーOS無料
VoiceOvermacOS・iOS✅ 標準搭載
NVDAWindows✅ 無料
TalkBackAndroid✅ 標準搭載

VoiceOverの起動方法(Mac): Command + F5 で起動・終了できます。Tabキーでフォーカス移動・Ctrl + Option + 矢印キーで読み上げ操作が可能です。

8.3 キーボードのみで操作できるか確認する

  1. マウスを使わずにTabキーだけでページ全体を操作できるか確認します。
  2. フォーカスが常に見えているか確認します。
  3. Enterキー・スペースキーでボタンやリンクを操作できるか確認します。
  4. Escapeキーでモーダルやメニューを閉じられるか確認します。

9. アクセシビリティ実装チェックリスト

セマンティックなHTMLタグ(header・nav・main・article・footer)を使っているか

見出しタグ(h1〜h6)の階層が正しく、h1が1ページに1つだけか

すべての画像にalt属性が設定されているか(装飾画像は alt=""

フォームの <input><label> が関連付けられているか

キーボードのみでサイト全体を操作できるか

フォーカスリングが常に見えているか(outline: none を単独で設定していないか)

スキップリンクを設置しているか

ハンバーガーメニューに aria-expanded・aria-label を設定しているか

テキストと背景のコントラスト比が4.5:1以上か(大きいテキストは3:1以上)

色だけで情報を伝えていないか(アイコンやテキストも併用しているか)

prefers-reduced-motion でアニメーション軽減設定に対応しているか

Lighthouseのアクセシビリティスコアを確認したか


まとめ

今回はポートフォリオサイトのアクセシビリティ対応として、スクリーンリーダー・キーボード操作・コントラスト比を中心に解説しました。ポイントをまとめると:

  • セマンティックなHTMLタグを使うことがアクセシビリティの第一歩
  • 見出しの階層を守り <h1> は1ページに1つだけにする
  • 画像のalt属性は内容を説明・装飾画像は空文字列にする
  • outline: none を単独で設定せずキーボードフォーカスを常に見えるようにする
  • スキップリンクでキーボードユーザーのナビゲーション移動を助ける
  • aria-expandedaria-labelaria-live でスクリーンリーダーに状態を伝える
  • グレーのテキストは #767676 以上の濃さにしてコントラスト比4.5:1を確保する
  • prefers-reduced-motion でアニメーションが苦手なユーザーへの配慮を忘れない

次の記事では、ポートフォリオサイトの最終仕上げとして、公開前に確認すべきことをまとめたチェックリストをお届けします。コード品質・SEO・パフォーマンス・セキュリティ・アクセシビリティの観点でサイトを総点検する方法を解説します。お楽しみに!

コメント

タイトルとURLをコピーしました