JavaScript
素のJavaScriptでタブ切り替え(タブパネル作成)
タブパネルを素のJavaScriptを使って(jQueryなしで)作成する方法についてご紹介します。
できるだけHTMLの仕様に基づいたものとしています。JavaScriptはクリックしたときの動作のためだけに用いていて、ほとんどはCSSで実現している形です。
デモ/タブパネルとは
タブパネルは、次のデモのようにタブで中身を切り替えられるユーザーインタフェースのことです。
タブAの中身
タブBの中身
タブCの中身
タブパネルのメリット
タブパネルのメリットは、ユーザーが同じ位置で中身を切り替えて見ることができるという点です。例えばコンテンツA、コンテンツB、コンテンツCをそれぞれ縦に並べると、見比べるときには、上下に移動しなければなりませんが、タブパネルの場合、移動が必要なくなります。
直感的にわかりやすいというのもあるのと、リンクでページを切り替える場合に比べると、表示の切り替わりが早いというのもあります。
タブパネルのデメリット
選択されているタブ以外は、CSSのdisplay: none
で非表示にしますので、デフォルトで非表示になっているコンテンツは、GoogleがSEO上評価してくれないというリスクがあります。
ソースコードと解説
HTML
<div class="tab-wrapper" role="tablist">
<div class="tab">
<input id="tab-a" type="radio" name="tab-radio" role="tab" class="tab-input" value="usage" checked="">
<h2 class="tab-label-heading selected"><label class="tab-label" for="tab-a">タブA</label></h2>
</div>
<div class="tab">
<input id="tab-b" type="radio" name="tab-radio" role="tab" class="tab-input" value="type">
<h2 class="tab-label-heading"><label class="tab-label" for="tab-b">タブB</label></h2>
</div>
<div class="tab">
<input id="tab-c" type="radio" name="tab-radio" role="tab" class="tab-input" value="maker">
<h2 class="tab-label-heading"><label class="tab-label" for="tab-c">タブC</label></h2>
</div>
</div>
<div class="tab-panel panel-a" role="tabpanel">
<div><p>タブAの中身</p></div>
</div>
<div class="tab-panel panel-b" role="tabpanel">
<div><p>タブBの中身</p></div>
</div>
<div class="tab-panel panel-c" role="tabpanel">
<div><p>タブCの中身</p></div>
</div>
タブ部分にラジオボタンを用いているのはHTMLの意味論、アクセシビリティのことをできるだけ考えてのことです。JavaScriptを用いた本実装の場合、例えばdiv要素だけを使っても見た目と動作的には変わらないものができますが、クリックしたら択一式で選択される、という機能を果たすものとしてラジオボタンがHTMLでは用意されているので、それを用いるのが仕様に対しては素直だと考えます。どのくらい、この配慮が意味をなしているかはよくわかっていません。
role="tablist"
, role="tab"
, role="tabpanel"
は、アクセシビリティのためのWAI-ARIAで定められている仕様で、タブであることを支援技術に伝えることができます。aria-selected="true"
という、どのタブが選択された状態であるかを伝えるための仕様も定められているのですが、ラジオボタンを用いていればそこまでは不要です。
また、タブに見出し要素を用いているのも、文書構造への配慮です。タブパネルの中に見出しを入れるという実装も見かけることがありますが、タブ部分と同じ文言を書くことになり冗長になるので、このようにタブに見出し要素を使った方がシンプルになると思います。
タブパネル部分は、div要素を3つ並べて、選択されてないパネルはCSSで非表示にしています。
CSS
/*タブを横並びに*/
.tab-wrapper{
display: flex;
}
.tab:not(:last-of-type) {
margin-right: 2px;
}
/*ラジオボタンを全て非表示に*/
input[name="tab-radio"] {
display: none;
}
.tab-label {
display: block;
}
.tab-label{
background-color: #b4bdbf;
color: #525252;
cursor: pointer;
font-size: 16px;
padding: 10px 20px;
transition: .3s;
}
.tab-label:hover{
opacity: .7;
}
/* 選択されたタブの見た目 */
.selected>.tab-label{
color: #000;
background-color: #e2e8eb;
transition: .3s;
}
/*タブパネル*/
.tab-panel{
background-color: #e2e8eb;
height: 170px;
}
.tab-panel>div{
display: flex;
height: 100%;
align-items: center;
justify-content: center;
}
/*タブパネルの初期状態として選ばれてないものを非表示に*/
.panel-b,
.panel-c{
display: none;
}
JavaScript
const tab_elements = document.getElementsByName('tab-radio');
const tab_panel_a = document.querySelector('.panel-a');
const tab_panel_b = document.querySelector('.panel-b');
const tab_panel_c = document.querySelector('.panel-c');
tab_elements.forEach( tab_element => {
tab_element.addEventListener('click', function(){
if (tab_element.id == 'tab-a'){
tab_panel_a.style.display = 'block';
tab_panel_b.style.display = 'none';
tab_panel_c.style.display = 'none';
}else if (tab_element.id == 'tab-b'){
tab_panel_a.style.display = 'none';
tab_panel_b.style.display = 'block';
tab_panel_c.style.display = 'none';
}else if (tab_element.id == 'tab-c'){
tab_panel_a.style.display = 'none';
tab_panel_b.style.display = 'none';
tab_panel_c.style.display = 'block';
}
// 選択されたかどうかを示すクラス名「selected」の付与と削除
tab_elements.forEach( tab_element => {
tab_element.nextElementSibling.classList.remove('selected');
});
tab_element.nextElementSibling.classList.add('selected');
});
});
ラジオボタンをクリックしたら紐づけられた見出しにクラス名selected
をつけるということをしています。ラジオボタンはCSSで非表示にしているためクリッカブルな部分がないように思われるかもしれませんが、label要素とidによってHTMLで紐づけているので、この場合、label要素をクリックしてもラジオボタンがクリックされたものと認識して動作するというのがJavaScriptの仕様です。
nextElementSibling
は、隣接する次の要素を取得するプロパティです。ラジオボタンの次にh2
があるので、そのh2
にselected
のクラス名が付与されます。
まとめ
できるだけHTMLの仕様に基づいて、JavaScriptを使ってタブパネルを作る方法をご説明しました。JavaScriptはクリックしたときの動作のためだけに用いていて、ほとんどはCSSで実現している形です。JavaScriptでの実装と比べてHTMLの構造に制約があるものの、CSSだけで実装することも実はできるので、ご紹介しています。