ボトムナビゲーションBottom navigation
スマートフォンの画面の下端に固定し、アイコンと短い名前を3〜5個並べたメニュー。アプリの主要な画面を親指ひとつで行き来させる。
表示例
アイコン: Font Awesome 7 Free(fa-solid / fa-regular)
別名・英語表記
- タブバー
- ボトムナビ
- 下部ナビゲーション
- ボトムメニュー
- 下のメニュー
- 画面下のアイコンメニュー
- Bottom navigation
実装例
AIへの指示文
「ボトムナビゲーション(Bottom navigation)」を実装してください。
## これは何か
スマートフォンの画面の下端に固定し、アイコンと短い名前を3〜5個並べたメニュー。アプリの主要な画面を親指ひとつで行き来させる。
## 使いどころ
- スマートフォン向けのサービスで、主要な行き先が3〜5個に収まり、どれも頻繁に行き来するとき
- ハンバーガーメニューに畳むと使われなくなる主要な画面を、常に見える場所に出したいとき
## 実装の要件
- nav[aria-label] > ul > li > a(アイコン + 文字)の構成にする
- position: fixed; left: 0; right: 0; bottom: 0; で下端に留め、padding-bottom: env(safe-area-inset-bottom) で端末の安全領域を空ける
- 項目の幅は数で均等に割り(flex: 1)、当たり判定の高さは 48px 以上にする
- 本文の padding-bottom と html の scroll-padding-bottom に、メニューの高さを入れる
- 項目は3〜5個に絞る。6個以上になったら、使う頻度の低いものをマイページなどの中へ移す
- アイコンだけにしない。ハートと星のように、形だけでは「お気に入り」か「評価」か決まらない。短い名前を必ず添える
- 固定すると本文の最後の行がメニューの下に隠れる。本文側の下端に、メニューの高さぶんの padding-bottom を足す
- iPhone では画面下端のホームインジケーターに項目が重なる。viewport の meta に viewport-fit=cover を指定し、padding-bottom: env(safe-area-inset-bottom) で下を空ける
- PC の広い画面でもそのまま出すと、視線から遠い下端にメニューが残る。広い画面ではグローバルナビやサイドバーに切り替える
## アクセシビリティの要件
- nav 要素で囲み、aria-label を付ける。行き先へのリンクなので role="tablist" / role="tab" にしない(タブは同じページの中の表示を切り替える部品)
- 現在地のリンクに aria-current="page" を付け、色だけでなく線や太字でも示す
- アイコンは aria-hidden="true" にし、リンクの名前は見えている文字から取らせる
- 固定した帯の下にフォーカスした要素が隠れないよう、html に scroll-padding-bottom を指定する(WCAG 2.2 の 2.4.11 隠されないフォーカス(最低限))
## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。
```html
<div class="x-bottom-nav">
<div class="x-bottom-nav__page" aria-hidden="true">
<span class="x-bottom-nav__bar"></span>
<span class="x-bottom-nav__bar x-bottom-nav__bar--short"></span>
<span class="x-bottom-nav__bar"></span>
</div>
<nav class="x-bottom-nav__nav" aria-label="メインメニュー">
<ul class="x-bottom-nav__list">
<li><a class="x-bottom-nav__a" href="/" aria-current="page"><i class="fa-solid fa-house" aria-hidden="true"></i><span class="x-bottom-nav__t">ホーム</span></a></li>
<li><a class="x-bottom-nav__a" href="/search/"><i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i><span class="x-bottom-nav__t">さがす</span></a></li>
<li><a class="x-bottom-nav__a" href="/favorites/"><i class="fa-regular fa-heart" aria-hidden="true"></i><span class="x-bottom-nav__t">お気に入り</span></a></li>
<li><a class="x-bottom-nav__a" href="/mypage/"><i class="fa-regular fa-user" aria-hidden="true"></i><span class="x-bottom-nav__t">マイページ</span></a></li>
</ul>
</nav>
</div>
```
```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-bottom-nav,
.x-bottom-nav *:not([class*="fa-"]),
.x-bottom-nav *:not([class*="fa-"])::before,
.x-bottom-nav *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
/* 外枠はスマートフォンの画面を切り取った見本。実際は nav だけを置き、
position: fixed; left: 0; right: 0; bottom: 0; で画面の下端に留める */
.x-bottom-nav {
display: flex;
flex-direction: column;
width: 300px;
height: 180px;
border: 1px solid #e3e6ea;
border-radius: 16px;
background: #f3f4f6;
overflow: hidden;
}
.x-bottom-nav__page {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
padding: 18px 16px;
}
.x-bottom-nav__bar {
display: block;
height: 10px;
border-radius: 5px;
background: #dde1e6;
}
.x-bottom-nav__bar--short {
width: 60%;
}
.x-bottom-nav__nav {
border-top: 1px solid #e3e6ea;
background: #fff;
box-shadow: 0 -2px 8px rgba(27, 32, 40, 0.06);
/* iPhone の下端のバーに項目が重ならないよう、端末の安全領域ぶん下を空ける
(viewport の meta に viewport-fit=cover を指定したときに効く) */
padding-bottom: env(safe-area-inset-bottom, 0px);
}
.x-bottom-nav__list {
display: flex;
margin: 0;
padding: 0;
list-style: none;
}
.x-bottom-nav__list > li {
flex: 1 1 0;
min-width: 0;
}
.x-bottom-nav__a {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
min-height: 56px;
padding: 6px 2px;
color: #606a7b;
font-size: 11px;
text-decoration: none;
}
.x-bottom-nav__a .fa-solid,
.x-bottom-nav__a .fa-regular {
font-size: 18px;
}
.x-bottom-nav__t {
white-space: nowrap;
}
.x-bottom-nav__a:hover {
color: #1d4ed8;
}
/* 現在地は色だけでなく、上端の線と太字でも示す */
.x-bottom-nav__a[aria-current="page"] {
color: #1d4ed8;
font-weight: 700;
box-shadow: inset 0 3px 0 #1d4ed8;
}
.x-bottom-nav__a:focus-visible {
outline: 2px solid #1d4ed8;
outline-offset: -4px;
}
```
## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。
使いどころ
- スマートフォン向けのサービスで、主要な行き先が3〜5個に収まり、どれも頻繁に行き来するとき
- ハンバーガーメニューに畳むと使われなくなる主要な画面を、常に見える場所に出したいとき
注意点
- 項目は3〜5個に絞る。6個以上になったら、使う頻度の低いものをマイページなどの中へ移す
- アイコンだけにしない。ハートと星のように、形だけでは「お気に入り」か「評価」か決まらない。短い名前を必ず添える
- 固定すると本文の最後の行がメニューの下に隠れる。本文側の下端に、メニューの高さぶんの padding-bottom を足す
- iPhone では画面下端のホームインジケーターに項目が重なる。viewport の meta に viewport-fit=cover を指定し、padding-bottom: env(safe-area-inset-bottom) で下を空ける
- PC の広い画面でもそのまま出すと、視線から遠い下端にメニューが残る。広い画面ではグローバルナビやサイドバーに切り替える
アクセシビリティの要点
- nav 要素で囲み、aria-label を付ける。行き先へのリンクなので role="tablist" / role="tab" にしない(タブは同じページの中の表示を切り替える部品)
- 現在地のリンクに aria-current="page" を付け、色だけでなく線や太字でも示す
- アイコンは aria-hidden="true" にし、リンクの名前は見えている文字から取らせる
- 固定した帯の下にフォーカスした要素が隠れないよう、html に scroll-padding-bottom を指定する(WCAG 2.2 の 2.4.11 隠されないフォーカス(最低限))