【jQuery】タブ切り替え実装サンプル集(上下連動、下タブを押すとスクロールして上に、 外部ページからのリンクIDも可能)
- 更新
- デザインのメモ

少し複雑な『タブ切り替え』を実装してみました。
▽今回の実装テーマ
- 上下のタブの連動
- 下のタブを押すとスクロールして上にスクロールして移動する
- 外部ページからのリンクIDを可能にする。リンクIDのタブを開いた状態にする

なんだか難しそうですねー

できる自信がありませんねー
シンプルなタブ切り替え
コードを見る(HTML・CSS・jQuery)
HTML
<div class="tabBox">
<div class="tabArea">
<div class="one_tab">
<a href="#s_01_tab01"><span class="tab_inner">Tab1</span></a>
</div>
<div class="one_tab">
<a href="#s_01_tab02"><span class="tab_inner">Tab2</span></a>
</div>
<div class="one_tab">
<a href="#s_01_tab03"><span class="tab_inner">Tab3</span></a>
</div>
</div>
</div><!-- /.tabBox -->
<div class="contents">
<div id="s_01_tab01" class="tab_main">
<div class="innerArea">Tab1 text</div>
</div><!-- /#tab01 -->
<div id="s_01_tab02" class="tab_main">
<div class="innerArea">Tab2 text</div>
</div><!-- /#tab02 -->
<div id="s_01_tab03" class="tab_main">
<div class="innerArea">Tab3 text</div>
</div><!-- /#tab03 -->
</div><!--contents-->
CSS
.tabBox .tabArea {
width: 100%;
height: 80px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-end;
}
.tabBox .tabArea .one_tab {
width: 32.5%;
}
.tabBox .tabArea .one_tab a {
display: block;
text-decoration: none;
transition-duration: 0.3s;
text-align: center;
color: #fff;
cursor: pointer;
}
.tabBox .tabArea .one_tab a:hover {
opacity: 0.7;
text-decoration: none;
}
.tabBox .tabArea .one_tab .tab_inner {
display: flex;
justify-content: center;
align-items: center;
height: 60px;
transition-duration: 0.3s;
}
.tabBox .tabArea .one_tab:nth-child(1) .tab_inner {
background-color: #2b2a27;
}
.tabBox .tabArea .one_tab:nth-child(2) .tab_inner {
background-color: #e8dc6a;
color: #2b2a27;
}
.tabBox .tabArea .one_tab:nth-child(3) .tab_inner {
background-color: #f3efe6;
color: #2b2a27;
}
.tabBox .tabArea .one_tab a.select .tab_inner {
height: 80px;
}
.contents .tab_main {
display: none;
padding: 50px 25px;
text-align: center;
min-height: 280px;
border: 2px solid #2b2a27;
transition-duration: 0.3s;
}
.tab_main.is_show {
display: block;
}
.tab_main:nth-child(1).is_show {
border: 2px solid #2b2a27;
}
.tab_main:nth-child(2).is_show {
border: 2px solid #e8dc6a;
}
.tab_main:nth-child(3).is_show {
border: 2px solid #e8e3d8;
}
/* 動きを減らす設定のとき */
@media (prefers-reduced-motion: reduce) {
.tabBox .tabArea .one_tab a, .tabBox .tabArea .one_tab .tab_inner { transition: none; }
}
jQuery
$(function() {
var tabMenu = function() {
/**
* 変数の指定
* $tab_area : tabの親要素のjQueryオブジェクト
* $content : tabによって切り替わる要素のjQueryオブジェクト
* TAB_ACTIVE_CLASS : tabが選択されたスタイルを変更するclass名
* CONTENT_SHOW_CLASS : contentを表示させるためのclass名
* id_arr : $contentのIDを配列に格納
*/
var $tab_area = $('.tabArea');
var $content = $('.contents .tab_main');
var TAB_ACTIVE_CLASS = 'select';
var CONTENT_SHOW_CLASS = 'is_show';
var id_arr = $content.map(function() { return '#' + $(this).attr('id');}).get();
/**
* 該当するhashデータがある場合、hashを返す
* 該当とは id_arr[] に含まれるもの
* @return {string} 該当する場合
* @return {false} 該当しない(存在しない)場合
*/
var getHash = function() {
var hash = window.location.hash;
var index = id_arr.indexOf(hash);
if (index === -1) {
return false;
} else {
return id_arr[index];
}
};
/**
* ページ読み込み時に実行
* 1. hashがあれば、hashをhrefに持つタブのスタイル変更(専用のclass付与)
* 2. hashがあれば、hashをidに持つコンテンツを表示(専用のclassを付与)
* 3. hashがなければ、タブの先頭が選択された状態とする
*/
var initialize = function() {
var hash = getHash();
if (hash) {
$tab_area.find('a[href="'+hash+'"]').addClass(TAB_ACTIVE_CLASS); // 1
$(hash).addClass(CONTENT_SHOW_CLASS); // 2
$(window).on('load',function(){
setTimeout(function(){
// 移動先を100px上にずらす
var adjust = 100;
// スクロールの速度
var speed = 400; // ミリ秒
// 移動先を取得
var target = $(hash);
// 移動先を調整
var position = target.offset().top - adjust;
// スムーススクロール
$('body,html').animate({scrollTop:position}, speed, 'swing');
},100);
});
} else {
$tab_area.find('.one_tab:first > a').addClass(TAB_ACTIVE_CLASS); // 3
$($content[0]).addClass(CONTENT_SHOW_CLASS); // 3
}
};
/**
* タブのクリックイベント
* 1. クリックされたタブのhref, 該当するcontentを取得
* 2. 既にクリック済みの状態であればスキップ
* 3. 一旦タブ・contentの専用classを全削除
* 4. クリックしたタブのスタイルを変更、該当するcontentを表示(それぞれ専用のclassを付与)
*/
var addEvent = function() {
$tab_area.find('a').on('click', function() {
// 1
var href = $(this).attr('href');
var $targetContent = $(href);
// 2
if ($(this).hasClass(TAB_ACTIVE_CLASS)) {
return false;
}
// 3
$tab_area.find('a').removeClass(TAB_ACTIVE_CLASS);
$content.removeClass(CONTENT_SHOW_CLASS);
// 4
$(this).addClass(TAB_ACTIVE_CLASS);
$targetContent.addClass(CONTENT_SHOW_CLASS);
return false;
});
};
return [initialize(), addEvent()];
};
// 実行
tabMenu();
});
上下のタブの連動
コードを見る(HTML・CSS・jQuery)
HTML
<div class="s_02_tabBox">
<div class="tabArea">
<button type="button" id="s_02_tab01" class="s_02_one_tab select"><span class="tab_inner">Tab1</span></button>
<button type="button" id="s_02_tab02" class="s_02_one_tab"><span class="tab_inner">Tab2</span></button>
<button type="button" id="s_02_tab03" class="s_02_one_tab"><span class="tab_inner">Tab3</span></button>
</div>
</div><!-- /.s_02_tabBox -->
<div class="s_02_contents">
<div class="s_02_tab_main is_show">
<div class="innerArea">Tab1 text</div>
</div>
<div class="s_02_tab_main">
<div class="innerArea">Tab2 text</div>
</div>
<div class="s_02_tab_main">
<div class="innerArea">Tab3 text</div>
</div>
</div><!--s_02_contents-->
<!-- ▼Tab under▼ -->
<div class="s_02_tabBox">
<div class="tabArea bottom">
<button type="button" class="s_02_one_tab select"><span class="tab_inner">Tab1</span></button>
<button type="button" class="s_02_one_tab"><span class="tab_inner">Tab2</span></button>
<button type="button" class="s_02_one_tab"><span class="tab_inner">Tab3</span></button>
</div>
</div><!-- /.s_02_tabBox -->
CSS
.s_02_tabBox .tabArea {
width: 100%;
height: 80px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-end;
}
.s_02_tabBox .tabArea .s_02_one_tab {
width: 32.5%;
}
.s_02_tabBox .tabArea .s_02_one_tab {
display: block;
border: 0;
padding: 0;
background: none;
font: inherit;
text-decoration: none;
transition-duration: 0.3s;
text-align: center;
color: #fff;
cursor: pointer;
}
.s_02_tabBox .tabArea .s_02_one_tab:hover {
opacity: 0.7;
text-decoration: none;
}
.s_02_tabBox .tabArea .s_02_one_tab .tab_inner {
display: flex;
justify-content: center;
align-items: center;
height: 60px;
transition-duration: 0.3s;
}
.s_02_tabBox .tabArea .s_02_one_tab:nth-child(1) .tab_inner {
background-color: #2b2a27;
}
.s_02_tabBox .tabArea .s_02_one_tab:nth-child(2) .tab_inner {
background-color: #e8dc6a;
color: #2b2a27;
}
.s_02_tabBox .tabArea .s_02_one_tab:nth-child(3) .tab_inner {
background-color: #f3efe6;
color: #2b2a27;
}
.s_02_tabBox .tabArea .s_02_one_tab.select .tab_inner {
height: 80px;
}
.s_02_tabBox .tabArea.bottom {
align-items: flex-start;
}
.s_02_contents .s_02_tab_main {
display: none;
padding: 50px 25px;
text-align: center;
min-height: 280px;
border: 2px solid #2b2a27;
transition-duration: 0.3s;
}
.s_02_tab_main.is_show {
display: block;
}
.s_02_tab_main:nth-child(1).is_show {
border: 2px solid #2b2a27;
}
.s_02_tab_main:nth-child(2).is_show {
border: 2px solid #e8dc6a;
}
.s_02_tab_main:nth-child(3).is_show {
border: 2px solid #e8e3d8;
}
/* 動きを減らす設定のとき */
@media (prefers-reduced-motion: reduce) {
.s_02_tabBox .tabArea .s_02_one_tab, .s_02_tabBox .tabArea .s_02_one_tab .tab_inner { transition: none; }
}
jQuery
$(function() {
var TabList = function(elParent,contentsParent) {
this.elParent = $(elParent);
this.el = this.elParent.find('.s_02_one_tab');
this.contentsParent = $(contentsParent);
this.contents = this.contentsParent.find('.s_02_tab_main');
};
TabList.prototype.fn = function() {
var that = this;
this.el.on('click', function() {
var index = $(this).index();
that.elParent.each(function(){
$('.s_02_one_tab',this).removeClass('select').eq(index).addClass('select');
});
that.contents.removeClass('is_show').eq(index).addClass('is_show');
});
};
var syncTab = new TabList('.s_02_tabBox', '.s_02_contents');
syncTab.fn();
});
下のタブを押すとスクロールして上にスクロールして移動する
コードを見る(HTML・CSS・jQuery)
HTML
<div class="s_03_tabBox">
<div class="tabArea">
<button type="button" id="s_03_tab01" class="s_03_one_tab select"><span class="tab_inner">Tab1</span></button>
<button type="button" id="s_03_tab02" class="s_03_one_tab"><span class="tab_inner">Tab2</span></button>
<button type="button" id="s_03_tab03" class="s_03_one_tab"><span class="tab_inner">Tab3</span></button>
</div>
</div><!-- /.s_03_tabBox -->
<div class="s_03_contents">
<div class="s_03_tab_main is_show">
<div class="innerArea">Tab1 text</div>
</div>
<div class="s_03_tab_main">
<div class="innerArea">Tab2 text</div>
</div>
<div class="s_03_tab_main">
<div class="innerArea">Tab3 text</div>
</div>
</div><!--s_03_contents-->
<!-- ▼Tab under▼ -->
<div class="s_03_tabBox">
<div class="tabArea bottom">
<button type="button" class="s_03_one_tab select"><span class="tab_inner">Tab1</span></button>
<button type="button" class="s_03_one_tab"><span class="tab_inner">Tab2</span></button>
<button type="button" class="s_03_one_tab"><span class="tab_inner">Tab3</span></button>
</div>
</div><!-- /.s_03_tabBox -->
CSS
.s_03_tabBox .tabArea {
width: 100%;
height: 80px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-end;
}
.s_03_tabBox .tabArea .s_03_one_tab {
width: 32.5%;
}
.s_03_tabBox .tabArea .s_03_one_tab {
display: block;
border: 0;
padding: 0;
background: none;
font: inherit;
text-decoration: none;
transition-duration: 0.3s;
text-align: center;
color: #fff;
cursor: pointer;
}
.s_03_tabBox .tabArea .s_03_one_tab:hover {
opacity: 0.7;
text-decoration: none;
}
.s_03_tabBox .tabArea .s_03_one_tab .tab_inner {
display: flex;
justify-content: center;
align-items: center;
height: 60px;
transition-duration: 0.3s;
}
.s_03_tabBox .tabArea .s_03_one_tab:nth-child(1) .tab_inner {
background-color: #2b2a27;
}
.s_03_tabBox .tabArea .s_03_one_tab:nth-child(2) .tab_inner {
background-color: #e8dc6a;
color: #2b2a27;
}
.s_03_tabBox .tabArea .s_03_one_tab:nth-child(3) .tab_inner {
background-color: #f3efe6;
color: #2b2a27;
}
.s_03_tabBox .tabArea .s_03_one_tab.select .tab_inner {
height: 80px;
}
.s_03_tabBox .tabArea.bottom {
align-items: flex-start;
}
.s_03_contents .s_03_tab_main {
display: none;
padding: 50px 25px;
text-align: center;
min-height: 280px;
border: 2px solid #2b2a27;
transition-duration: 0.3s;
}
.s_03_tab_main.is_show {
display: block;
}
.s_03_tab_main:nth-child(1).is_show {
border: 2px solid #2b2a27;
}
.s_03_tab_main:nth-child(2).is_show {
border: 2px solid #e8dc6a;
}
.s_03_tab_main:nth-child(3).is_show {
border: 2px solid #e8e3d8;
}
/* 動きを減らす設定のとき */
@media (prefers-reduced-motion: reduce) {
.s_03_tabBox .tabArea .s_03_one_tab, .s_03_tabBox .tabArea .s_03_one_tab .tab_inner { transition: none; }
}
jQuery
$(function() {
var TabList = function(elParent,contentsParent) {
this.elParent = $(elParent);
this.el = this.elParent.find('.s_03_one_tab');
this.contentsParent = $(contentsParent);
this.contents = this.contentsParent.find('.s_03_tab_main');
};
TabList.prototype.fn = function() {
var that = this;
this.el.on('click', function() {
var index = $(this).index();
that.elParent.each(function(){
$('.s_03_one_tab',this).removeClass('select').eq(index).addClass('select');
});
that.contents.removeClass('is_show').eq(index).addClass('is_show');
if($(this).parent().hasClass('bottom')){
scrollToHash();
}
});
function scrollToHash(){
var speed = 400;
var target = that.contentsParent;
var position = target.offset().top - 100;
$('body,html').animate({scrollTop:position}, speed, 'swing');
return false;
}
};
var syncTab = new TabList('.s_03_tabBox', '.s_03_contents');
syncTab.fn();
});
【完成版】上下連動、下タブを押すとスクロールして上に、 外部ページからのリンクIDも可能
コードを見る(HTML・CSS・jQuery)
HTML
<div class="tabBox">
<div class="tabArea">
<div class="one_tab">
<a href="#s_04_tab01"><span class="tab_inner">Tab1</span></a>
</div>
<div class="one_tab">
<a href="#s_04_tab02"><span class="tab_inner">Tab2</span></a>
</div>
<div class="one_tab">
<a href="#s_04_tab03"><span class="tab_inner">Tab3</span></a>
</div>
</div>
</div><!-- /.tabBox -->
<div class="contents">
<div id="s_04_tab01" class="tab_main">
<div class="innerArea">Tab1 text</div>
</div><!-- /#tab01 -->
<div id="s_04_tab02" class="tab_main">
<div class="innerArea">Tab2 text</div>
</div><!-- /#tab02 -->
<div id="s_04_tab03" class="tab_main">
<div class="innerArea">Tab3 text</div>
</div><!-- /#tab03 -->
</div><!--contents-->
<!-- ▼Tab under▼ -->
<div class="tabBox">
<div class="tabArea bottom">
<div class="one_tab">
<a href="#s_04_tab01"><span class="tab_inner">Tab1</span></a>
</div>
<div class="one_tab">
<a href="#s_04_tab02"><span class="tab_inner">Tab2</span></a>
</div>
<div class="one_tab">
<a href="#s_04_tab03"><span class="tab_inner">Tab3</span></a>
</div>
</div>
</div><!-- /.tabBox -->
CSS
.tabBox .tabArea {
width: 100%;
height: 80px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-end;
}
.tabBox .tabArea .one_tab {
width: 32.5%;
}
.tabBox .tabArea .one_tab a {
display: block;
text-decoration: none;
transition-duration: 0.3s;
text-align: center;
color: #fff;
cursor: pointer;
}
.tabBox .tabArea .one_tab a:hover {
opacity: 0.7;
text-decoration: none;
}
.tabBox .tabArea .one_tab .tab_inner {
display: flex;
justify-content: center;
align-items: center;
height: 60px;
transition-duration: 0.3s;
}
.tabBox .tabArea .one_tab:nth-child(1) .tab_inner {
background-color: #2b2a27;
}
.tabBox .tabArea .one_tab:nth-child(2) .tab_inner {
background-color: #e8dc6a;
color: #2b2a27;
}
.tabBox .tabArea .one_tab:nth-child(3) .tab_inner {
background-color: #f3efe6;
color: #2b2a27;
}
.tabBox .tabArea .one_tab a.select .tab_inner {
height: 80px;
}
.tabBox .tabArea.bottom {
align-items: flex-start;
}
.contents .tab_main {
display: none;
padding: 50px 25px;
text-align: center;
min-height: 280px;
border: 2px solid #2b2a27;
transition-duration: 0.3s;
}
.tab_main.is_show {
display: block;
}
.tab_main:nth-child(1).is_show {
border: 2px solid #2b2a27;
}
.tab_main:nth-child(2).is_show {
border: 2px solid #e8dc6a;
}
.tab_main:nth-child(3).is_show {
border: 2px solid #e8e3d8;
}
/* 動きを減らす設定のとき */
@media (prefers-reduced-motion: reduce) {
.tabBox .tabArea .one_tab a, .tabBox .tabArea .one_tab .tab_inner { transition: none; }
}
jQuery
$(function() {
var tabMenu = function() {
/**
* 変数の指定
* $tab_area : tabの親要素のjQueryオブジェクト
* $content : tabによって切り替わる要素のjQueryオブジェクト
* TAB_ACTIVE_CLASS : tabが選択されたスタイルを変更するclass名
* CONTENT_SHOW_CLASS : contentを表示させるためのclass名
* id_arr : $contentのIDを配列に格納
*/
var $tab_area = $('.tabArea');
var $content = $('.contents .tab_main');
var TAB_ACTIVE_CLASS = 'select';
var CONTENT_SHOW_CLASS = 'is_show';
var id_arr = $content.map(function() { return '#' + $(this).attr('id');}).get();
/**
* 該当するhashデータがある場合、hashを返す
* 該当とは id_arr[] に含まれるもの
* @return {string} 該当する場合
* @return {false} 該当しない(存在しない)場合
*/
var getHash = function() {
var hash = window.location.hash;
var index = id_arr.indexOf(hash);
if (index === -1) {
return false;
} else {
return id_arr[index];
}
};
/**
* ページ読み込み時に実行
* 1. hashがあれば、hashをhrefに持つタブのスタイル変更(専用のclass付与)
* 2. hashがあれば、hashをidに持つコンテンツを表示(専用のclassを付与)
* 3. hashがなければ、タブの先頭が選択された状態とする
*/
var initialize = function() {
var hash = getHash();
if (hash) {
$tab_area.find('a[href="'+hash+'"]').addClass(TAB_ACTIVE_CLASS); // 1
$(hash).addClass(CONTENT_SHOW_CLASS); // 2
$(window).on('load',function(){
setTimeout(function(){
// 移動先を100px上にずらす
var adjust = 100;
// スクロールの速度
var speed = 400; // ミリ秒
// 移動先を取得
var target = $(hash);
// 移動先を調整
var position = target.offset().top - adjust;
// スムーススクロール
$('body,html').animate({scrollTop:position}, speed, 'swing');
},100);
});
} else {
$tab_area.find('.one_tab:first > a').addClass(TAB_ACTIVE_CLASS); // 3
$($content[0]).addClass(CONTENT_SHOW_CLASS); // 3
}
};
/**
* タブのクリックイベント
* 1. クリックされたタブのhref, 該当するcontentを取得
* 2. 既にクリック済みの状態であればスキップ
* 3. 一旦タブ・contentの専用classを全削除
* 4. クリックしたタブのスタイルを変更、該当するcontentを表示(それぞれ専用のclassを付与)
*/
var addEvent = function() {
$tab_area.find('a').on('click', function() {
// 1
var href = $(this).attr('href');
var $targetContent = $(href);
// 2
if ($(this).hasClass(TAB_ACTIVE_CLASS)) {
return false;
}
// 3
$tab_area.find('a').removeClass(TAB_ACTIVE_CLASS);
$content.removeClass(CONTENT_SHOW_CLASS);
// 4
$(this).addClass(TAB_ACTIVE_CLASS);
$targetContent.addClass(CONTENT_SHOW_CLASS);
return false;
});
};
return [initialize(), addEvent()];
};
// 実行
tabMenu();
});
// 下のタブをクリックした場合に処理
$(function(){
$('.tabArea.bottom a[href^="#"]').click(function() {
// 移動先を100px上にずらす
var adjust = 100;
// スクロールの速度
var speed = 400; // ミリ秒
// アンカーの値取得
var href= $(this).attr("href");
// 移動先を取得
var target = $(href == "#" || href == "" ? 'html' : href);
// 移動先を数値で取得
var position = target.offset().top - adjust;
// スムーススクロール
$('body,html').animate({scrollTop:position}, speed, 'swing');
return false;
});
});
// タブ連動
$(function(){
// tab01
$('.tabArea .one_tab:nth-child(1) a').on('click',function(){
$('.tabArea .one_tab:nth-child(1) a').addClass('select');
});
$('.tabArea .one_tab:not(:nth-child(1)) a').on('click',function(){
$('.tabArea .one_tab:nth-child(1) a').removeClass('select');
});
// tab02
$('.tabArea .one_tab:nth-child(2) a').on('click',function(){
$('.tabArea .one_tab:nth-child(2) a').addClass('select');
});
$('.tabArea .one_tab:not(:nth-child(2)) a').on('click',function(){
$('.tabArea .one_tab:nth-child(2) a').removeClass('select');
});
// tab03
$('.tabArea .one_tab:nth-child(3) a').on('click',function(){
$('.tabArea .one_tab:nth-child(3) a').addClass('select');
});
$('.tabArea .one_tab:not(:nth-child(3)) a').on('click',function(){
$('.tabArea .one_tab:nth-child(3) a').removeClass('select');
});
});
【確認】外部ページからのリンクIDを可能にする。リンクIDのタブを開いた状態にする
URL の末尾に「#s_04_tab01」〜「#s_04_tab03」を付けて、【完成版】の見本をひらきます。そのタブが開いた状態になり、タブの位置までスクロールします。
メモ
jQueryのことで何かわからないことがあればjQueryの日本語リファレンスサイトがあるので一度チェックしてみるといろいろ解決できたりしますよ。
さいごに

できたのですか?

できましたー



