タブは、ページのコンテンツを切り替える場合に使われるUIで、画面の切り替えも容易でにできます。
CSSだけで実装することも可能ですが、JavaScriptを使うと記述がシンプルで分かりやすいのでおすすめです。
そんなタブの特徴については、以下の記事もあわせてご覧ください。
そんなタブをページ内に複数設置する場合、JavaScriptの .querySelectorAll()
を使って1つのコードで動くスニペットについて解説していきます。
.querySelectorAll()
querySelectorAll()
は、CSSセレクタで指定ができるので、HTMLとCSSが分かっていれば扱えてしまいます。
ANDやORの検索も可能で、:hover
や:active
の擬似要素にも対応しています。
これ以外にも、JavaScriptにはgetElementById()
や、getElemetnsByClassName()
で、HTML要素を取得できるメソッドはありすが、このquerySelectorAll()
は、jQueryを扱うときのような記述で、HTML要素をセレクタ指定することができます。
.querySelectorAll()で複数タブのサンプル
JavaScriptの .querySelectorAll()
を使った、複数のタブのサンプルです。
Section1-1
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-2
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-3
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section2-1
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ
Section2-2
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ
Section2-3
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ
Section3-1
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ
Section3-2
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ
Section3-3
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ
3つのタブを設置していますが、4つ・5つなど数を増やす場合もHTMLを追加するだけで動いてくれます。
タブのコード
HTMLは、1個1個の各タブ全体を section
タグで作り、その中の nav
がタブの見出し。そして、tabs__body
のclass名をつけた div
タグで、切り替えで表示される中身を作ります。
<section class="someTabs" data-tabs>
<nav class="tabs__nav">
<a href="#" class="tabs__item active" data-tab>Section1-1</a>
<a href="#" class="tabs__item" data-tab>Section1-2</a>
<a href="#" class="tabs__item" data-tab>Section1-3</a>
</nav>
<div class="tabs__body">
<div class="tabs__content active" data-tab-content><p>Section1-1</p><p>山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな</p></div>
<div class="tabs__content" data-tab-content><p>Section1-2</p><p>山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな</p></div>
<div class="tabs__content" data-tab-content><p>Section1-3</p><p>山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな</p></div>
</div>
</section>
<section class="someTabs" data-tabs>
<nav class="tabs__nav">
<a href="#" class="tabs__item active" data-tab>Section2-1</a>
<a href="#" class="tabs__item" data-tab>Section2-2</a>
<a href="#" class="tabs__item" data-tab>Section2-3</a>
</nav>
<div class="tabs__body">
<div class="tabs__content active" data-tab-content><p>Section2-1</p><p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ</p></div>
<div class="tabs__content" data-tab-content><p>Section2-2</p><p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ</p></div>
<div class="tabs__content" data-tab-content><p>Section2-3</p><p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎ</p></div>
</div>
</section>
<section class="someTabs" data-tabs>
<nav class="tabs__nav">
<a href="#" class="tabs__item active" data-tab>Section3-1</a>
<a href="#" class="tabs__item" data-tab>Section3-2</a>
<a href="#" class="tabs__item" data-tab>Section3-3</a>
</nav>
<div class="tabs__body">
<div class="tabs__content active" data-tab-content><p>Section3-1</p><p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ</p></div>
<div class="tabs__content" data-tab-content><p>Section3-2</p><p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ</p></div>
<div class="tabs__content" data-tab-content><p>Section3-3</p><p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、こ</p></div>
</div>
</section>
JavaScriptは、初めに「tabsElems」の関数宣言で、querySelectorAll()
を使って、「data-tabs」の名前の属性を持つ要素を指定します。
そして、ループを作り.addEventListenerのクリックイベントで「active」のクラス名を .remove
と .add
で切り替えます。
const tabsElems = document.querySelectorAll("[data-tabs]");
if(tabsElems.length > 0){
for (let i = 0; i < tabsElems.length; i++) {
let tab = tabsElems[i];
let tabBtnElems = tab.querySelectorAll("[data-tab]");
let tabContentElems = tab.querySelectorAll("[data-tab-content]");
for (let i = 0; i < tabBtnElems.length; i++) {
let tabBtn = tabBtnElems[i];
let tabContent = tabContentElems[i];
tabBtn.addEventListener("click", (e) => {
e.preventDefault();
for (let i = 0; i < tabBtnElems.length; i++) {
tabBtnElems[i].classList.remove('active');
tabContentElems[i].classList.remove('active');
}
tabBtn.classList.add('active');
tabContent.classList.add('active');
});
}
}
}
CSS
JavaScriptで表示・非表示を切り替えるので、CSSはシンプルです。
タブ見出しクリック時の表示は、keyframes
「fadein」アニメーションでスタイルを定義して、表示しています。
/* タブの表示・非表示 */
[data-tab-content]{
display: none
}
[data-tab-content].active{
display: block;
}
/* section同士の余白 */
section.someTabs {
margin-bottom: 40px;
border-bottom: solid 1px #eee;
padding-bottom: 30px;
}
section.someTabs:last-child {
margin: 0;
padding: 0;
border: none;
}
/* タブの中身のpタグの余白 */
.tabs__content p {
margin-bottom: 10px;
}
.tabs__content p:last-child {
margin-bottom: 0;
}
/* タブの見出し */
nav.tabs__nav {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
width: 100%;
padding: 0;
margin: 0 0 1rem;
border: none;
box-shadow: 0 7px 34px rgb(50 50 93 / 10%), 0 3px 6px rgb(0 0 0 / 8%);
}
nav.tabs__nav a:first-child {
border-radius: 3px 0 0 3px;
border-right: solid 1px #eee;
}
nav.tabs__nav a:last-child {
border-radius: 0 3px 3px 0;
border-left: solid 1px #eee;
}
a.tabs__item {
display: inline-block;
width: calc(100%/3);
text-align: center;
transition: all 0.2s ease;
padding: 0;
line-height: 50px;
text-decoration: none;
background: #FFF;
}
a.tabs__item.active {
background: linear-gradient( 45deg , #bdb9ff, #67b8ff);
color: #FFF;
}
/* 表示のアニメーション */
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
}
}
.tabs__content.active {
animation: fadeIn 0.7s ease 0s 1 normal;
}