#はじめに
jQuery UI
や Bootstrap
のようなライブラリ/フレームワークを使用せずに、簡単なタブメニューを作成してみました。なるべく使い勝手が良く(カスタマイズしやすく)なるような仕様を想定しました。何かのお役に立てば幸いです。
#仕様
- スクリプトはなるべくhtmlに依存させない
- 表示・非表示・スタイルに関する操作は全てCSS側で行う
- 直接タブへリンクできるようにする (*1
- なるべく多くのブラウザで動作させる (*2
- JavaScript無効時も想定する
*1)
例えば別ページよりhttp://xxxx/#view
とリンクされた場合は、該当するタブとコンテンツをデフォルト表示
*2)
IE6以上で基本動作を確認しました(IETesterですが・・・)
#前提条件
- jQuery1系を使用
- タブのhrefと切り替えたい要素のidを一致させる(index.html#hashのようにはせずに#hashとする) (*3
*3)
このようなタブメニューであえてindex.html#hashのようにするケースは、あまり無いかと思うので考慮していません。
#ソースコード
<ul class="tabs">
<li><a href="#view1">タブ1</a></li>
<li><a href="#view2">タブ2</a></li>
<li><a href="#view3">タブ3</a></li>
<li><a href="#view4">タブ4</a></li>
</ul>
<div id="view1" class="tab-content">タブ1の中身です</div>
<div id="view2" class="tab-content">タブ2の中身です</div>
<div id="view3" class="tab-content">タブ3の中身です</div>
<div id="view4" class="tab-content">タブ4の中身です</div>
.tabs .is_active {
/* 何かタブを変更する設定 */
}
.tab-content {
display: none;
}
.tab-content.is_show {
display: block;
}
$(function() {
var tabMenu = function() {
/**
* 変数の指定
* $tabs : tabの親要素のjQueryオブジェクト
* $content : tabによって切り替わる要素のjQueryオブジェクト
* TAB_ACTIVE_CLASS : tabが選択されたスタイルを変更するclass名
* CONTENT_SHOW_CLASS : contentを表示させるためのclass名
* id_arr : $contentのIDを配列に格納
*/
var $tabs = $('.tabs');
var $content = $('.tab-content');
var TAB_ACTIVE_CLASS = 'is_active';
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) {
$tabs.find('a[href="'+hash+'"]').addClass(TAB_ACTIVE_CLASS); // 1
$(hash).addClass(CONTENT_SHOW_CLASS); // 2
} else {
$tabs.find('li: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() {
$tabs.find('a').on('click', function() {
var href = $(this).attr('href'); // 1
var $targetContent = $(href); // 1
// 2
if ($(this).hasClass(TAB_ACTIVE_CLASS)) {
return false;
}
// 3
$tabs.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();
});
実際の動作・ソースコードは以下で確認できます
##一口メモ
- class名を変えたい場合は、スクリプトの上の方にある大文字で書いている変数を変更します
-
.tab-content
はcssで非表示をデフォルトにしておきます -
.tab-content
に.is_show
で表示させるスタイルを適用させます - tab(aタグ)は
.is_active
で選択時のスタイルを適用させます
#JavaScript無効時に対応する
上記だけではJavaScript無効時には対応できていません。対応には以下のようなパターンが考えられます。
※ここでの対応とは「コンテンツが全て表示される」ということを指します
- **
.js
**が取れる場合 - 専用のCSSを用意する
- スクリプトを改修する
##.jsが取れる場合
Modernizerなどで**.js
**(jsが有効状態を表すclass名が自動で付く)を取得できる場合は、.js .tab-content {display: none;}
とすればOKかと思います。
##専用のCSSを用意する
<noscript>
で専用のCSSファイルもしくは、<style>
タグを指定します。その中で.tab-content {display: block;}
を設定してやればOKかと思います。
html5からheadタグ内で
<noscript>
が使えるようになりました
##スクリプトを改修する
スクリプト内でデフォルトを非表示にさせるようします。例えば.is_hide
を用意し、動作に合わせて要素にクラスを付与するなど。ですが多くの場合、実行処理の順番により読み込み時に隠れるべき要素が一瞬表示されてしまいます。
#番外編
少しリッチなUIになるよう調整してみました。もちろん調整はCSSのみです。(css3を使っているのでモダンブラウザのみです)
【動作イメージ】
実際の動作・ソースコードは以下で確認できます
http://codepen.io/nekoneko-wanwan/pen/VverGR
#終わりに
ε ⌒ヘ⌒ヽフ
( ( ・ω・) これはブタ
しー し─J