タブを縦方向に並べ、クリックしたタブに応じて隣のコンテンツを切り替える方法を紹介します。今回は、タブを左側に配置する方法と、右側に配置する方法の2パターンを作成します。
左側にタブを配置する場合は、左のタブを選択すると右側の内容が切り替わります。右側に配置する場合はその逆で、右のタブを選択すると左側の内容が切り替わります。どちらも選択中のタブが青色になり、対応するコンテンツだけが表示されます。
タブはクリックだけでなく、キーボードの上下矢印キーでも切り替えられます。最初のタブから最後のタブへ、最後のタブから最初のタブへも移動でき、HomeキーとEndキーで先頭・末尾のタブを直接選択できます。タブを切り替えてもページ全体は再読み込みされません。
デモ
最初に表示されるコンテンツです。左側のタブをクリックすると、対応する内容に切り替わります。
2番目のコンテンツです。選択したタブの背景色が変わり、右側の表示内容が更新されます。
3番目のコンテンツです。タブを切り替えてもページ全体は再読み込みされません。
最初に表示されるコンテンツです。右側のタブをクリックすると、左側の内容が切り替わります。
2番目のコンテンツです。タブの配置を右側に変更しても、切り替え操作は同じです。
3番目のコンテンツです。選択中のタブだけが青色になり、対応する内容だけが表示されます。
1つ目は左側にタブを配置し、右側のコンテンツを切り替えます。2つ目は右側にタブを配置し、左側のコンテンツを切り替えます。どちらもタブ1〜3をクリックして表示を変更できます。キーボードでは上下の矢印キーでも切り替えられます。
コードをコピーして使おう!
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コードの設定 -->
<meta charset="UTF-8">
<!-- スマートフォンなどの画面幅に対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>縦型タブ切り替え(左側配置)</title>
<!-- 縦型タブのデザインを読み込む -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 縦型タブ切り替え全体 -->
<div class="vertical-tab-switch_wrap">
<!-- 左側のタブ一覧 -->
<div class="vertical-tab-switch_tabs" role="tablist" aria-label="左側タブの切り替え" aria-orientation="vertical">
<!-- 初期選択するタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-left-tab-1" aria-controls="vertical-tab-switch-left-panel-1" aria-selected="true" tabindex="0">
タブ1
</button>
<!-- 2番目のタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-left-tab-2" aria-controls="vertical-tab-switch-left-panel-2" aria-selected="false" tabindex="-1">
タブ2
</button>
<!-- 3番目のタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-left-tab-3" aria-controls="vertical-tab-switch-left-panel-3" aria-selected="false" tabindex="-1">
タブ3
</button>
</div>
<!-- 右側のコンテンツ領域 -->
<div class="vertical-tab-switch_panels">
<!-- タブ1に対応するコンテンツ。初期状態で表示する -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-left-panel-1" role="tabpanel" aria-labelledby="vertical-tab-switch-left-tab-1">
<div class="vertical-tab-switch_heading">タブ1の内容</div>
<p class="vertical-tab-switch_text">
最初に表示されるコンテンツです。左側のタブをクリックすると、対応する内容に切り替わります。
</p>
</div>
<!-- タブ2に対応するコンテンツ。初期状態では非表示 -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-left-panel-2" role="tabpanel" aria-labelledby="vertical-tab-switch-left-tab-2" hidden>
<div class="vertical-tab-switch_heading">タブ2の内容</div>
<p class="vertical-tab-switch_text">
2番目のコンテンツです。選択したタブの背景色が変わり、右側の表示内容が更新されます。
</p>
</div>
<!-- タブ3に対応するコンテンツ。初期状態では非表示 -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-left-panel-3" role="tabpanel" aria-labelledby="vertical-tab-switch-left-tab-3" hidden>
<div class="vertical-tab-switch_heading">タブ3の内容</div>
<p class="vertical-tab-switch_text">
3番目のコンテンツです。タブを切り替えてもページ全体は再読み込みされません。
</p>
</div>
</div>
</div>
<!-- タブのクリック・キーボード操作を読み込む -->
<script src="script.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コードの設定 -->
<meta charset="UTF-8">
<!-- スマートフォンなどの画面幅に対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>縦型タブ切り替え(右側配置)</title>
<!-- 縦型タブのデザインを読み込む -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 縦型タブ切り替え全体。rightクラスでタブを右側に配置する -->
<div class="vertical-tab-switch_wrap vertical-tab-switch_right">
<!-- 右側のタブ一覧 -->
<div class="vertical-tab-switch_tabs" role="tablist" aria-label="右側タブの切り替え" aria-orientation="vertical">
<!-- 初期選択するタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-right-tab-1" aria-controls="vertical-tab-switch-right-panel-1" aria-selected="true" tabindex="0">
タブ1
</button>
<!-- 2番目のタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-right-tab-2" aria-controls="vertical-tab-switch-right-panel-2" aria-selected="false" tabindex="-1">
タブ2
</button>
<!-- 3番目のタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-right-tab-3" aria-controls="vertical-tab-switch-right-panel-3" aria-selected="false" tabindex="-1">
タブ3
</button>
</div>
<!-- 左側のコンテンツ領域 -->
<div class="vertical-tab-switch_panels">
<!-- タブ1に対応するコンテンツ。初期状態で表示する -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-right-panel-1" role="tabpanel" aria-labelledby="vertical-tab-switch-right-tab-1">
<div class="vertical-tab-switch_heading">タブ1の内容</div>
<p class="vertical-tab-switch_text">
最初に表示されるコンテンツです。右側のタブをクリックすると、左側の内容が切り替わります。
</p>
</div>
<!-- タブ2に対応するコンテンツ。初期状態では非表示 -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-right-panel-2" role="tabpanel" aria-labelledby="vertical-tab-switch-right-tab-2" hidden>
<div class="vertical-tab-switch_heading">タブ2の内容</div>
<p class="vertical-tab-switch_text">
2番目のコンテンツです。タブの配置を右側に変更しても、切り替え操作は同じです。
</p>
</div>
<!-- タブ3に対応するコンテンツ。初期状態では非表示 -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-right-panel-3" role="tabpanel" aria-labelledby="vertical-tab-switch-right-tab-3" hidden>
<div class="vertical-tab-switch_heading">タブ3の内容</div>
<p class="vertical-tab-switch_text">
3番目のコンテンツです。選択中のタブだけが青色になり、対応する内容だけが表示されます。
</p>
</div>
</div>
</div>
<!-- タブのクリック・キーボード操作を読み込む -->
<script src="script.js"></script>
</body>
</html>
コードをコピーする場合 使用するコードのタブを選び、「このタブをコピー」をクリックすると、現在表示中のコードをコピーできます。 サンプル一式を取得する場合 HTML・CSSなどすべてのファイルが必要な場合は、「サンプル一式をダウンロード」をクリックしてください。
Q ダウンロードしたけど、これをネット上で動かすにはどうするの?
Googleアカウントがあれば、InfinityFreeで無料サーバーを作成して、ダウンロードしたサンプルをネット上で動かせます。
InfinityFreeを初めて利用する場合は①から、すでにサーバーを作成している場合は②へ進んでください。
ファイル構成と設置方法
縦型タブ切り替えは、タブを左側に配置する方法と、右側に配置する方法の2種類を用意しています。
どちらもHTML・CSS・JavaScriptの3ファイルで構成し、クリックやキーボード操作によってコンテンツを切り替えます。
2種類のサンプルは、それぞれ独立してダウンロードできます。
ファイル構成は共通ですが、タブの配置に合わせてHTMLとCSSの内容が異なります。
sample/
├── index.html
├── style.css
└── script.js
各ファイルの役割
index.htmlには、縦に並ぶ3つのタブボタンと、それぞれに対応するコンテンツを配置しています。
タブとコンテンツには個別のIDを設定し、選択したタブと表示先を対応付けています。
style.cssでは、タブ一覧とコンテンツの横並び配置、選択中のタブの背景色、文字サイズ、余白などを設定しています。
右側配置のサンプルでは、追加のCSSによってタブ一覧とコンテンツの左右位置を入れ替えています。
script.jsでは、選択されたタブの状態とコンテンツの表示・非表示を制御しています。
クリック操作に加えて、上下矢印キー・Homeキー・Endキーによる切り替えも処理しています。
設置方法・使い方
使用したい配置の「サンプル一式をダウンロード」をクリックし、ZIPファイルを展開してください。
展開後は、sampleフォルダ内のindex.html・style.css・script.jsを同じ階層に配置します。
index.htmlをブラウザで開くと、最初は「タブ1」のコンテンツが表示されます。
「タブ2」「タブ3」をクリックすると、対応する内容へ切り替わります。
キーボードでは、Tabキーで選択中のタブへ移動できます。
その状態で上下の矢印キーを押すと、前後のタブへ移動しながら表示内容が切り替わります。
左側配置と右側配置は別々のサンプルなので、両方を設置する必要はありません。
タブとコンテンツを対応させる仕組み
index.htmlでは、各タブのaria-controlsに、表示先となるコンテンツのIDを指定しています。
また、コンテンツ側のaria-labelledbyには、対応するタブのIDを指定しています。
左側配置の「タブ1」では、次のように設定しています。
<!-- 初期選択するタブ -->
<button class="vertical-tab-switch_tab" type="button" role="tab" id="vertical-tab-switch-left-tab-1" aria-controls="vertical-tab-switch-left-panel-1" aria-selected="true" tabindex="0">
タブ1
</button>
<!-- タブ1に対応するコンテンツ。初期状態で表示する -->
<div class="vertical-tab-switch_panel" id="vertical-tab-switch-left-panel-1" role="tabpanel" aria-labelledby="vertical-tab-switch-left-tab-1">
<div class="vertical-tab-switch_heading">タブ1の内容</div>
<p class="vertical-tab-switch_text">
最初に表示されるコンテンツです。左側のタブをクリックすると、対応する内容に切り替わります。
</p>
</div>
タブのaria-controls="vertical-tab-switch-left-panel-1"と、コンテンツのid="vertical-tab-switch-left-panel-1"が一致しています。
JavaScriptはこの対応関係を使用して、表示するコンテンツを判断します。
タブの文字はbutton要素内の「タブ1」、コンテンツのタイトルはvertical-tab-switch_heading、説明文はvertical-tab-switch_textの内容を書き換えることで変更できます。
IDを変更する場合は、タブのidとコンテンツのaria-labelledby、タブのaria-controlsとコンテンツのidを、それぞれ一致させてください。
右側配置では、IDのleft部分がrightになっています。
選択中のタブとコンテンツを切り替える処理
script.jsのactivateTab()は、選択されたタブを受け取り、すべてのタブとコンテンツの状態を更新する関数です。
選択されたタブにはaria-selected="true"を設定し、それ以外のタブにはfalseを設定します。
コンテンツ側では、対応するIDを持つ要素だけを表示します。
// 指定したタブを選択状態にする
function activateTab(targetTab, moveFocus) {
// すべてのタブの選択状態を更新する
tabs.forEach(function(tab) {
// 選択対象のタブかどうかを判定する
const isActive = tab === targetTab;
// 選択状態とキーボード操作時のフォーカス対象を更新する
tab.setAttribute("aria-selected", String(isActive));
tab.setAttribute("tabindex", isActive ? "0" : "-1");
});
// すべてのコンテンツの表示状態を更新する
panels.forEach(function(panel) {
// 対応するコンテンツだけを表示し、それ以外は非表示にする
panel.hidden = panel.id !== targetTab.getAttribute("aria-controls");
});
// キーボード操作では選択したタブへフォーカスを移動する
if (moveFocus) {
targetTab.focus();
}
}
panel.id !== targetTab.getAttribute("aria-controls")で、コンテンツのIDと選択中のタブの表示先を比較しています。
一致しないコンテンツにはhidden属性を設定し、一致するコンテンツからは取り除きます。
style.cssの.vertical-tab-switch_panel[hidden]にはdisplay: noneが指定されているため、選択されていないコンテンツは表示されません。
選択中のタブは、.vertical-tab-switch_tab[aria-selected="true"]によって青色の背景と白い文字に変わります。
選択時の背景色を変更したい場合は、このCSSのbackground: #2563ebを編集してください。
キーボードでタブを切り替える仕組み
script.jsでは、各タブにkeydownイベントを登録しています。
押されたキーに応じて次に選択するタブの位置を計算し、activateTab()を実行します。
// 現在のタブを移動先の初期値とする
let nextIndex = index;
if (event.key === "ArrowDown") {
// 下矢印キーで次のタブへ移動し、最後から最初へ戻る
nextIndex = (index + 1) % tabs.length;
} else if (event.key === "ArrowUp") {
// 上矢印キーで前のタブへ移動し、最初から最後へ戻る
nextIndex = (index - 1 + tabs.length) % tabs.length;
} else if (event.key === "Home") {
// Homeキーで最初のタブへ移動する
nextIndex = 0;
} else if (event.key === "End") {
// Endキーで最後のタブへ移動する
nextIndex = tabs.length - 1;
} else {
// 対応していないキーは通常の動作を維持する
return;
}
下矢印キーでは次のタブ、上矢印キーでは前のタブへ移動します。
% tabs.lengthを使っているため、最後のタブで下矢印キーを押すと最初に戻り、最初のタブで上矢印キーを押すと最後に移動します。
Homeキーでは最初のタブ、Endキーでは最後のタブを選択します。
移動先のタブにはJavaScriptでフォーカスも移動させるため、続けてキーボード操作ができます。
タブを4つ以上に増やす場合は、index.htmlへ対応するbutton要素とコンテンツを追加し、それぞれのIDを正しく対応させてください。
JavaScriptはタブの数をtabs.lengthから取得しているため、タブ数に合わせた数値の書き換えは不要です。
タブを左右に配置するCSS
左側配置では、style.cssのgrid-template-columnsによって、左側に160pxのタブ領域、右側に残りの幅のコンテンツ領域を作っています。
右側配置では、vertical-tab-switch_rightクラスを追加し、列の幅と各要素の配置先を変更しています。
/* =========================================
右側にタブを配置する場合
========================================= */
.vertical-tab-switch_right {
grid-template-columns: minmax(0, 1fr) 160px; /* 左側を残りの幅、右側のタブ幅を160pxにする */
}
/* =========================================
右側のタブ一覧
========================================= */
.vertical-tab-switch_right .vertical-tab-switch_tabs {
grid-column: 2; /* タブ一覧を2列目へ配置する */
grid-row: 1; /* タブ一覧を1行目へ配置する */
border-right: none; /* 基本配置の右側境界線を削除する */
border-left: 1px solid #dbe5f1; /* コンテンツとの左側境界線を付ける */
}
/* =========================================
左側のコンテンツ領域
========================================= */
.vertical-tab-switch_right .vertical-tab-switch_panels {
grid-column: 1; /* コンテンツを1列目へ配置する */
grid-row: 1; /* コンテンツを1行目へ配置する */
}
grid-template-columns: minmax(0, 1fr) 160pxでは、左側をコンテンツ領域、右側の160pxをタブ領域にしています。
grid-column: 2でタブ一覧を右側に、grid-column: 1でコンテンツを左側に配置します。
タブ領域を広くしたい場合は、160pxの数値を大きくしてください。
コンテンツ側の横幅は、その分だけ狭くなります。
全体の最大横幅は.vertical-tab-switch_wrapのmax-width: 680pxで調整できます。
また、タブの最小高さは.vertical-tab-switch_tabのmin-height: 64px、コンテンツ内の余白は.vertical-tab-switch_panelのpadding: 32pxで調整できます。
レスポンシブ対応
どちらのサンプルも、style.cssでwidth: 100%とmax-width: 680pxを指定しているため、設置先の横幅に合わせて全体が縮小します。
画面幅640px以下では、タブ領域の横幅を160pxから110pxに変更し、タブの文字サイズやコンテンツの余白も小さくしています。
右側配置では、次の設定によってタブを右側に維持したまま横幅を調整します。
/* 画面幅640px以下で基本のサイズを調整する */
.vertical-tab-switch_wrap {
grid-template-columns: 110px minmax(0, 1fr); /* 基本配置のタブ幅を110pxにする */
min-height: 240px; /* 全体の最小高さを240pxにする */
}
/* 右側配置では右側のタブ幅を110pxにする */
.vertical-tab-switch_right {
grid-template-columns: minmax(0, 1fr) 110px; /* 左側を残りの幅、右側のタブ幅を110pxにする */
}
上記はstyle.cssの@media (max-width: 640px)内にある設定です。
左側配置では110pxのタブ領域が左側に、右側配置では110pxのタブ領域が右側に配置されます。
640pxの数値を変更すると、スマートフォン向けのスタイルを適用する画面幅を調整できます。
タブ領域が狭い場合は110pxを大きくできますが、その分コンテンツの表示幅が小さくなります。
スマートフォンでもタブは縦並びのままで、左右の配置関係は変わりません。
コメント