jQueryでタブメニューをつくったときのメモ

jquery-tabmenu
Update

jQueryでタブメニューをつくってみました。タブの切り替えでつまづいたところとか、開閉式タブメニューを試したこととか、領域外クリックで閉じるようにしたこととかのメモです。サンプルも載せました。

基本のタブメニュー

まずはこちらを参考に、シンプルなタブメニューをつくります。

HTML

<div class="tabmenu">
    <ul class="tab">
        <li class="select">ひとつめのタブ</li>
        <li>ふたつめのタブ</li>
        <li>みっつめのタブ</li>
    </ul>
    <div class="content">
        <div>ひとつめのなかみ</div>
        <div class="hide">ふたつめのなかみふたつめのなかみ</div>
        <div class="hide">みっつめのなかみみっつめのなかみみっつめのなかみ</div>
    </div>
</div>

jQuery

$(function() {
    $('.tab li').click(function() {
        var tabnum = $('.tab li').index(this);
        $('.content div').css('display','none');
        $('.content div').eq(tabnum).css('display','block');
        $('.tab li').removeClass('select');
        $(this).addClass('select')
    });
});

CSS

.tabmenu{
    width: 60%;}

.tab{
    overflow: hidden;
    margin: 0;
    padding: 0;
    list-style: none;}

.tab li{
    background: #eee;
    cursor: pointer;
    display: inline-block;
    width: 20%;
    padding: .6em;}

    .tab li.select{
        background: #fd9;}

.content div{
    background: #fd9;
    height: 200px;
    padding: .6em;}

.hide{
    display:none;}

補足とサンプル

かんたんに補足します。

タブ(<ul class="tab">の中の<li>)をクリックすると、

$('.tab li').click(function() {

何番目の<li>をクリックしたか、その番号をtabnumという変数に代入する。

var tabnum = $('.tab li').index(this);

参考:eq(index) – jQuery 日本語リファレンス

要素集合から引数にインデックスを指定し、ひとつだけの要素を選択する。
インデックスは0から全要素数-1までの連番。

いったんコンテンツ部分(<div class="content">の中の<div>)を全部非表示にして、

$('.content div').css('display','none');

<div class="content">の中の、tabnum番目の<div>を表示する。

$('.content div').eq(tabnum).css('display','block');

いったん、全部のタブ<li>から、ハイライト用のクラスselectをとって、

$('.tab li').removeClass('select');

クリックされたタブ<li>にだけ、selectってクラスをつける。

$(this).addClass('select')

ここまでのサンプルです。

さいしょのタブサンプル

タブの切り替えがうまくいかないとき

今回つくったサンプルでは、タブの<li>の順番に対応した("tabnum"番目の)<div>を表示したり非表示にしたりして切り替えていますので、間に別の<div>が入ってしまうと、当然のことながらタブが正しく切り替わらなくなります。

例えばこのブログはWordPressでつくっているのですが、コンテンツ部分の<div>の中にウィジェットやカスタムメニューを入れて動作を確認したときにタブの切り替えがうまくいかなくて、このことに気づくまでちょっと悩んでしまいました。

以下、うまくいかなかったときの例を載せておきます。

HTML

<div class="tabmenu">
    <ul class="tab">
        <li class="select">ひとつめのタブ</li>
        <li>ふたつめのタブ</li>
        <li>みっつめのタブ</li>
    </ul>
    <div class="content">
        <div>ひとつめのなかみ
            <div class="sub">ひとつめのなかみのなかみ(実際はこれがふたつめのdiv要素)</div>
        </div>
        <div class="hide">ふたつめのなかみふたつめのなかみ(実際はこれがみっつめのdiv要素)</div>
        <div class="hide">みっつめのなかみみっつめのなかみみっつめのなかみ</div>
    </div>
</div>

jQueryとCSSはかわりません。

そこで、コンテンツ部分に何を入れても困ってしまわないよう、表示・非表示を切り替える部分を要素ではなくクラス名で指定することにします。

サンプル

ここまでのサンプルです。

うまく切り替えできないタブサンプル

コンテンツ部分にクラス名をつける

表示するコンテンツ部分(<div class="content">の中の<div>)に、showというクラス名をつけることにします。

HTML

<div class="tabmenu">
    <ul class="tab">
        <li class="select">ひとつめのタブ</li>
        <li>ふたつめのタブ</li>
        <li>みっつめのタブ</li>
    </ul>
    <div class="content">
        <div class="show">ひとつめのなかみ(クラス名showひとつめの要素)
            <div class="sub">ひとつめのなかみのなかみ(ここはクラス名showじゃない)</div>
        </div>
        <div class="show hide">ふたつめのなかみふたつめのなかみ(クラス名showふたつめの要素)</div>
        <div class="show hide">みっつめのなかみみっつめのなかみみっつめのなかみ(クラス名showみっつめの要素)</div>
    </div>
</div>

jQuery

$(function() {
    $('.tab li').click(function() {
        var tabnum = $('.tab li').index(this);
        $('.content .show').css('display','none');
        $('.content .show').eq(tabnum).css('display','block');
        $('.tab li').removeClass('select');
        $(this).addClass('select')
    });
});

CSSはかわりません。

サンプル

ここまでのサンプルです。

クラスをつけたタブサンプル

これで中身に何を入れても困らなくなりました。

最初はなかみが閉じている状態にする

それでは、表示するコンテンツ部分(<div class="content">の中の<div>)ぜんぶに、hideってクラス名をつけます。

<div class="tabmenu">
	<ul class="tab">
		<li class="select">ひとつめのタブ</li>
		<li>ふたつめのタブ</li>
		<li>みっつめのタブ</li>	
	</ul>
	<div class="content">
		<div class="show hide">ひとつめのなかみ
			<div class="sub">ひとつめのなかみのなかみ</div>
		</div>
		<div class="show hide">ふたつめのなかみふたつめのなかみ</div>
		<div class="show hide">みっつめのなかみみっつめのなかみみっつめのなかみ</div>
	</div>
</div>  

jQueryとCSSはかわりません。

サンプル

ここまでのサンプルです。

最初閉じてるタブサンプル

コンテンツ部分を開閉できるようにする

最初だけコンテンツ部分が閉じているタブメニューを、こんどは自由に開閉できるようにします。

HTMLはかわりません。

jQuery

3行目以降がif, elseと分岐しています。追加したのはifの中身のほうです。

$(function() {
	$(".tab li").click(function(){
		if ($(this).attr('class') == 'select') {
		$('.content .show').css('display','none');
		$('.tab li').removeClass('select');
		} 
			else {
				var tabnum = $('.tab li').index(this);
				$('.content .show').css('display','none');
				$('.content .show').eq(tabnum).css('display','block');
				$('.tab li').removeClass('select');
				$(this).addClass('select')
				} 
	});
});

CSS

CSSはこれまでと同じですが、このタブは開閉できるよ、ということがわかるように、以下のようにタブ名の右側のさんかくを付け加えました。

    .tab li:after{
        content:"▼";
        padding-left: 1em;}

    .tab li.select:after{
        content:"▲";
        padding-left: 1em;}

補足とサンプル

ifの中身。ハイライトされているタブ(コンテンツ部分が表示されているタブ)がクリックされたら、

if ($(this).attr('class') == 'select') {

コンテンツを非表示にして、

$('.content .show').css('display','none');

クラス名selectを消す、という内容です。

$('.tab li').removeClass('select');
} 

elseの中身はこれまで通り(タブと対応するコンテンツ部分を開く、という内容)で、こちらが、ハイライトされていないタブがクリックされたときの動作になります。

ここまでのサンプルです。

開閉できるタブサンプル

コンテンツ部分に閉じるボタンをつける

スクロールが必要なくらいにコンテンツの中身が多い場合は、ボタンがあると便利かと思います。

HTML

<div class="tabmenu">
	<ul class="tab">
		<li>ひとつめのタブ</li>
		<li>ふたつめのタブ</li>
		<li>みっつめのタブ</li>
	</ul>
	<div class="content">
		<div class="show hide">ひとつめのなかみ
			<div class="sub">ひとつめのなかみのなかみ</div>
			<p class="close">とじる</p>
		</div>
		<div class="show hide">ふたつめのなかみふたつめのなかみ
			<p class="close">とじる</p>
		</div>
		<div class="show hide">みっつめのなかみみっつめのなかみみっつめのなかみ
			<p class="close">とじる</p>
		</div>
	</div>
</div>

jQuery

以下を追加します。

$('.close').click(function() {
    $('.content .show').css('display','none');
    $('.tab li').removeClass('select');
});

CSS

以下、ボタン部分を付け加えただけです。

.close{
    width:20%;
    background:#d38;
    border-radius: 4px;
    color: #fdfdfd;
    text-align: center;
    cursor: pointer;}

補足とサンプル

ボタン(クラス名close)をクリックしたら、

$('.close').click(function() {

コンテンツ部分(showというクラスがついているとこ)を非表示にして、

$('.content .show').css('display','none');

タブからハイライト用のクラスselectを消す。

$('.tab li').removeClass('select');
});

ここまでのサンプルです。

閉じるボタンをつけたタブサンプル

領域外をクリックすると閉じる

さいごに、タブメニューの領域外をクリックするとコンテンツ部分を閉じるようにします。レイアウトによっては便利な仕様かと思います。

jQuery

以下を追加します。

$('.tabmenu').hover(
    function(){menu_hover = true;}, 
    function(){menu_hover = false;}
);

$('body').click(function() {
        if (menu_hover == false) {
        $('.content .show').css('display','none');
        $('.tab li').removeClass('select');
        }
 });

補足とサンプル

タブメニュー上にマウスカーソルがあるとき、

$('.tabmenu').hover(

変数menu_hovertrueとする。

function(){menu_hover = true;}, 

タブメニュー上にマウスカーソルがないときは、変数menu_hoverfalseとする。

function(){menu_hover = false;}
);

body内のタブメニュー以外のどこかがクリックされたら、

$('body').click(function() {
if (menu_hover == false) {

開いているコンテンツ部分(.show)を非表示にして、タブからハイライト用のクラスselectを消す。

$('.content .show').css('display','none');
    $('.tab li').removeClass('select');
    }
});

参考:

hover(over, out) – jQuery 日本語リファレンス

マウスホバーの動きをシミュレートします。
マウスカーソルが要素の上に乗った時に、第一引数に渡した関数を実行します。マウスが要素から外れ>た時には第二引数が実行されます。

もうひとつ補足:CSSのこと

このタブメニュー領域外のクリックイベントがiPhoneのSafariでうまく動かなかったので、調べました。以下、参考記事です。

今つくっているサンプルではbodyにクリックイベントを追加していますので、CSSに以下の記述を加えれば良いのですが…こうすると、マウスカーソルがいつもポインタ(指のやつ)になってしまいます。

body{
    cursor:pointer;}

なので、実装するときには、メディアクエリで幅を指定するなどしたほうがいいかと思います。たとえば、iPhoneとiPad(縦)でちゃんと動けばいいということであれば、以下のようにするなど。

@media(max-width:768px){
    body{
        cursor:pointer;}
}

ここまでのサンプルです。

領域外クリックで閉じるタブサンプル

さいごに

このたびこのブログをスマートフォン(とiPad)からみたときにタブメニューを表示させるようにしました。少ないスペースを活用できていいですね。でも、iPhone以外では見た目も動作も検証できていないので、おかしなところがたくさんあったら教えていただけるととっても嬉しいです。