アクティブの動きも加わって、アクティブになったメニューが”より”わかりやすくなります。
タブの切り替えに動きを少し付けたいと思っている方は、是非参考にしてみてください。
.querySelectorAll()
querySelectorAll()
は、指定したセレクターの条件と一致したHTML要素を全て返すメソッドです。
elementList = parentNode.querySelectorAll(selectors);
要素を全て返すメソッドなので、この記事ではこのメソッドで取得した「タブのメニュー」と「タブで表示されるコンテンツ」の2つを for
文 のループ処理で作っています。
アクティブになったタブメニューの背景が動くサンプル
早速サンプルです。
「Section1-1」〜「Section1-3」のメニュー部分で現在地でONになっている背景が、クリックされたメニューに移動して表示されます。
Section1-1
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-2
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-3
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-1
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-2
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
Section1-3
山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。住みにくさが高じると、安い所へ引き越したくなる。どこへ越しても住みにくいと悟った時、詩が生れて、画が出来る。山路を登りな
サンプルは2つの独立したタブなので、背景もそれぞれのタブ内で移動します。
yahooのトップページをスマホで見た時、ニュースジャンル切り替え用のタブUIの動きと同じイメージのUIです。
実装の手順と方法
コードの解説の前に、実装の手順と方法について解説します。
まずはじめに、設置したい場所にHTMLでコードを記述します。
<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>
<a class="Tabs__presentation-slider" role="presentation"></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="">Section1-1</a>
<a href="#" class="tabs__item" data-tab="">Section1-2</a>
<a href="#" class="tabs__item" data-tab="">Section1-3</a>
<a class="Tabs__presentation-slider" role="presentation"></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>
次にJavaScriptを記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
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を記述して、見た目を整えましょう。
[data-tab-content]{
display: none
}
[data-tab-content].active{
display: block;
}
nav.tabs__nav {
position: relative;
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%);
border-radius: 3px;
background: #FFF;
}
a.tabs__item {
width: calc(100% / 3);
display: flex;
justify-content: center;
height: 50px;
align-items: center;
text-decoration: none;
}
a.tabs__item.active {
position: relative;
z-index: 1;
color: #FFF;
}
.tabs__item:first-child.active ~ .Tabs__presentation-slider {
transform: translateX(0) scaleX(0.333);
}
.tabs__item:nth-child(2).active ~ .Tabs__presentation-slider {
transform: translateX(33.333%) scaleX(0.333);
}
.tabs__item:nth-child(3).active ~ .Tabs__presentation-slider {
transform: translateX(calc(33.333% * 2)) scaleX(0.333);
}
.Tabs__presentation-slider {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
transform-origin: 0 0;
transition: transform 0.25s;
background: linear-gradient( 45deg , #bdb9ff, #67b8ff);
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
}
}
.tabs__content.active {
animation: fadeIn 0.7s ease 0s 1 normal;
}
ざっくりとしたコードの解説
コードは、HTML・JavaScript・CSSの3種類です。順に解説していきます。
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>
<a class="Tabs__presentation-slider" role="presentation"></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="">Section1-1</a>
<a href="#" class="tabs__item" data-tab="">Section1-2</a>
<a href="#" class="tabs__item" data-tab="">Section1-3</a>
<a class="Tabs__presentation-slider" role="presentation"></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>
JavaScript
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はシンプルです。
一見、JavaScriptでアクティブのタブを動かすと思いきや、CSSでアクティブの表示を切り替えています。
左右に動く背景は、「tabs__item」の○番目にそれぞれ「active」のclass名が当たった時にスタイルをあてる nth-child()
を使って、position:absolute;
で指定した「Tabs__presentation-slider」のclassを transform
プロパティで右に左に動かします。
[data-tab-content]{
display: none
}
[data-tab-content].active{
display: block;
}
nav.tabs__nav {
position: relative;
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%);
border-radius: 3px;
background: #FFF;
}
a.tabs__item {
width: calc(100% / 3);
display: flex;
justify-content: center;
height: 50px;
align-items: center;
text-decoration: none;
}
a.tabs__item.active {
position: relative;
z-index: 1;
color: #FFF;
}
.tabs__item:first-child.active ~ .Tabs__presentation-slider {
transform: translateX(0) scaleX(0.333);
}
.tabs__item:nth-child(2).active ~ .Tabs__presentation-slider {
transform: translateX(33.333%) scaleX(0.333);
}
.tabs__item:nth-child(3).active ~ .Tabs__presentation-slider {
transform: translateX(calc(33.333% * 2)) scaleX(0.333);
}
.Tabs__presentation-slider {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
transform-origin: 0 0;
transition: transform 0.25s;
background: linear-gradient( 45deg , #bdb9ff, #67b8ff);
}
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
}
}
.tabs__content.active {
animation: fadeIn 0.7s ease 0s 1 normal;
}
タブの選択後、表示されるコンテンツのブロックは @keyframes fadeIn
でアニメーションを作り、「active」のclassが付与されると、下からほわっと浮き上がるように表示させています。
さいごに
いかがでしたでしょうか?
タブはページのコンテンツを切り替える場合に使われるUIで、画面の切り替えも容易でにできます。
比較的簡単に設置できるUIなので、是非引き出しの一つとしてこの記事のタブも是非チェックしてみてください。