タブコンテンツ

タブボタンをクリックすることで、表示する内容を切り替えるタブコンテンツも、CSSだけでできちゃいます。コンテンツの切り替わり方のバリエーションや、タブボタンで表示レイアウトを切り替えるみたいな使い方など、CSSで作るタブコンテンツについてのまとめです:)。
CSSで切り替える仕組み
CSSで切り替えを行うためには、ちょっとした下ごしらえが必要なので、まずはその仕組みについて、下の仕組みがよくわかるサンプルのソースコードを見ながら要点を解説です。
HTML
まずはタブボタンと、それに付随するコンテンツを設置します。
タブボタンに<label>
を使うのがポイントです:)。
<ul class="tabBtn">
<li><label for="tab-1">タブ1</label></li>
<li><label for="tab-2">タブ2</label></li>
<li><label for="tab-3">タブ3</label></li>
<li><label for="tab-4">タブ4</label></li>
<li><label for="tab-5">タブ5</label></li>
</ul>
<div class="tabContents">
<section class="section-1">タブコンテンツ1</section>
<section class="section-2">タブコンテンツ2</section>
<section class="section-3">タブコンテンツ3</section>
<section class="section-4">タブコンテンツ4</section>
<section class="section-5">タブコンテンツ5</section>
</div>
次に、コンテンツを切り替えるスイッチの役割となる<input type="radio">
(ラジオボタン)を5つ、上のソースコードの手前に設置します。
<input type="radio" name="switch" id="tab-1" checked>
<input type="radio" name="switch" id="tab-2">
<input type="radio" name="switch" id="tab-3">
<input type="radio" name="switch" id="tab-4">
<input type="radio" name="switch" id="tab-5">
name属性の値を統一して、ラジオボタンをひとつのグループにします(ここではswitch
に統一しました)。こうすることで、<input type="radio">
がラジオボタン然とします、つまりどれかひとつボタンをチェックしたら他のボタンのチェックが外れるようになります。
それから<input>
のid属性の値を、<label>
のfor属性の値と同じにして、タブボタンとラジオボタンを関連付けます。
最後に、ひとつめの<input>
にはchecked属性を付けて、初期状態ではタブコンテンツ1が開いているようにしておきます。
以上で下ごしらえ完了!
CSS
そして、以降の指定が、コンテンツの表示/非表示を切り替えるための仕組みの部分になります。
まずは、タブボタンを切り替えた時の、ボタンのスタイルを指定します。
#tab-1:checked ~ .tabBtn label[for="tab-1"],
#tab-2:checked ~ .tabBtn label[for="tab-2"],
#tab-3:checked ~ .tabBtn label[for="tab-3"],
#tab-4:checked ~ .tabBtn label[for="tab-4"],
#tab-5:checked ~ .tabBtn label[for="tab-5"] {
background: #dc6688;
}
1行めを分解して見てみます。
#tab-1:checked
- id属性が
tab-1
で、チェックされている要素。 ~
~
(一般兄弟結合子)と言って、この記号を挟んで、左側のセレクタに後続する兄弟要素(同じ階層にある要素)である右側のセレクタを選択する。.tabBtn
- class属性が
tabBtn
の要素。 label[for="tab-1"]
- for属性が
tab-1
のlabel要素。
まとめると、「チェックされている#tab-1
要素に後続する、同じ階層にある.tabBtn
要素の中の、for属性がtab-1
のlabel要素」にbackground: #dc6688
を指定するって事になります。
要するに「1つめのラジオボタンがチェックされてる時は、1つめのタブボタンの背景を赤くする」ということ;D。

タブボタンを切り替えた時のコンテンツのスタイルもタブボタンと同じ要領で、「チェックされている#tab-1
要素に後続する、同じ階層にある.tabContents
要素の中の、.section-1
要素」というように、タブコンテンツを特定します。
.tabContents section {
opacity: .1;
}
#tab-1:checked ~ .tabContents .section-1,
#tab-2:checked ~ .tabContents .section-2,
#tab-3:checked ~ .tabContents .section-3,
#tab-4:checked ~ .tabContents .section-4,
#tab-5:checked ~ .tabContents .section-5 {
opacity: 1;
background: white;
}
チェックされていない時は透明(ここでは仕組みが見えるように半透明)にしておき、チェックされている時は不透明にすることで、表示/非表示を切り替えてるって寸法です;)。
:target
を使ってタブコンテンツ
上の「仕組みがよくわかるサンプル」では、ラジオボタンと:checked擬似クラスを使ってコンテンツの表示/非表示を切り替えてましたが、アンカーリンクの仕組みを使っても、同じように切り替える事ができます。
例えばURLの末尾に#contents-1
と付けてリンクすると、ページ内の<div id="contents-1">
の位置へリンクする事ができますよね。id属性を持った要素はすべてアンカーポイントとなって、その要素の場所へリンクできるようになります。
そんなアンカーリンクされている要素に、スタイルを適用する事ができるのが:target疑似クラス。
以下のように指定すれば、URLの末尾が#contents-1
としてアクセスした時に、contents-1
というid属性を持った要素を赤いボーダーで囲みます。
#contents-1:target {
border: 2px solid #dc6688;
}
URLを利用してスタイルを適用しているので、アンカーリンクする度に特定の要素のスタイルを切り替えることが可能です。しかもURLが切り替わるから、ブラウザの戻るボタンで履歴を辿る事もできちゃいます。タブコンテンツの内容が濃い場合にはこちらの方法が持ってこいかもしれませんねー:D。

#
の値によって、タブボタンの色が変わる先ほどの、仕組みがよくわかるサンプルで:checked
で切り替えてた部分を、:target
で切り替わるように修正してみましょう。
HTML
<input type="radio">
だったところを<div>
に置き換えます。あくまでスイッチの役割を担う空っぽdiv要素になります。id属性はそのままに、name属性の代わりにclass属性でswitch
という値を付与しました。
<input type="radio" name="switch" id="tab-1" checked>
⇓
<div id="tab-1" class="switch"></div>
タブボタンは<label>
から<a>
に置き換えて、for属性でinput要素と紐付けてたところを、今度はhref属性にして、前述の<div>
へそれぞれリンクするようにします。
<li><label for="tab-1">タブ1</label></li>
⇓
<li><a href="#tab-1">タブ1</a></li>
CSS
アンカーをクリックすると、ウィンドウの位置がその要素の位置まで移動しちゃいますが、その要素にdisplay: none
を指定すれば移動しなくなります。
.switch {
display: none;
}
あとは、HTMLに倣ってlabel
だったところをa
に、for
だったところをhref
に、:checked
だったところを:target
に置き換えれば完了ー!
.tabBtn li label { ... }
.tabBtn li label:hover { ... }
⇓
.tabBtn li a { ... }
.tabBtn li a:hover { ... }
label
をa
に置き換え#tab-1:checked ~ .tabBtn li [for="tab-1"] { ... }
⇓
#tab-1:target ~ .tabBtn li [href="#tab-1"] { ... }
:checked
を:target
に、for
をhref
に置き換え#tab-1:checked ~ .tabContents .section-1 { ... }
⇓
#tab-1:target ~ .tabContents .section-1 { ... }
:checked
を:target
に置き換えいくつかタブを切り替えた後でブラウザの戻るボタンを押してみてください。URLを移動することでタブの表示を切り替えてるので、タブ切り替えが履歴として残るため、切り替える前のタブに戻ることができるんですね;)。
アニメーションして切り替わる
タブコンテンツにコンテンツを入れてみました。
タブコンテンツも、マウスオーバーエフェクトの時みたく、transition
を使って切り替わり方をアレンジすれば、印象的な表現ができちゃいます:)。
スライドして切り替わる
タブボタンの切り替えに合わせて、<div class="tabContents">
の位置を上下にズラせば、スクロールコンテンツみたいなものもお手のもの。

上図のように、あらかじめtransform: translateY()
で、タブボタンに対応するコンテンツの位置を指定しておきます。例えば下記なら、「タブ2」がチェックされてる時には、.tabContents
を上へ20%※ズラす、ということ。※.tabContents
全体の高さを100%とした20%分。
#tab-2:checked ~ .tabContents {
transform: translateY(-20%);
}
これをタブコンテンツ分(このサンプルでは5つ)用意し、transition
を適用すれば、上下にスライドしながらコンテンツが切り替わるようになります。
あれれ…、タブコンテンツがタブボタンの上に被さってタブボタンが押せなくなっちゃう…X(。。
こんな時は.tabBtn
にz-index
を指定して、手前に配置すれば安心。

.tabBtn {
position: relative;
z-index: 1;
}
z-index
はpositionプロパティにstatic
以外の値が指定してある要素でないと効果がないので、position: relative
も一緒に指定。
無事タブボタンが押せるようになりました:D!
横にスライドして切り替わる
タブコンテンツを横並びにして、transform: translateX()
で横へズラせば、横スライドもお手のもの。

.tabContents
の横幅をウィンドウ幅5つ分(500%)にして、その中にタブコンテンツを横並びにします。そのままだとスクロールバーが出てしまうので、全体を包む要素(ここではbody要素)にoverflow: hidden
を指定して、スクロールバーを出さないようにすればできあがり。
表示モード切り替え
ここまでは、いくつかのコンテンツをタブボタンで切り替えてましたが、タブボタンのON/OFFで、同一コンテンツのスタイルを変えるようにすれば、表示モード切り替えみたいな事もできます。
ここでは、「画像とテキスト全部入りのレイアウト」、「画像が主役のレイアウト」、「テキストが主役のレイアウト」の3タイプの表示モードを、タブボタンで切り替えてみます。
下記のような記述で、各モード専用のスタイルを用意しておけば、チェックされているタブボタンに合わせて、指定したスタイルが適用される仕組みです。
#normalList:checked ~ .menu elements {
/* 全部入り用のスタイル */
}
#imageList:checked ~ .menu elements {
/* 画像が主役用のスタイル */
}
#textList:checked ~ .menu elements {
/* テキストが主役用のスタイル */
}
アニメーションを加える
上のサンプルだと、transition
を指定してる所の、前のモードのスタイルがちょっと見えちゃったり、モードの切り替わり方がちょっとかっこわるいですよね…。もうちょっとスマートに、フェードイン・アウトで切り替わるようにしたいです。
以下のように、ちょっと間を置いてからフェードインするアニメーションを用意して、タブボタンが:checked
になった時に一度だけ再生するようにしてみます。
@keyframes fadeIn {
from, 30% { opacity: 0; }
to { opacity: 1; }
}
このアニメーションを、チェックされた時のコンテンツに適用します。
input:checked ~ .menu {
animation: fadeIn 1s;
}
ページが開いた時に一度だけフェードインしますが、タブボタンで切り替える時には、アニメーションが再生されませんね…:(。:checked
されるタブが切り替わっても「fadeIn」というアニメーションはすでに再生された後なので、同じ要素に二度は適用されないみたいです…。
そこで、下のサンプルでは、まったく同じアニメーションをもう2つ違う名前で用意して、「画像が主役の」と「テキストが主役の」には別のアニメーション名を指定し直します。
input:checked ~ .menu {
animation: fadeIn 1s;
}
#imageList:checked ~ .menu {
animation-name: fadeIn2;
}
#textList:checked ~ .menu {
animation-name: fadeIn3;
}
@keyframes fadeIn {
from, 30% { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeIn2 {
from, 30% { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeIn3 {
from, 30% { opacity: 0; }
to { opacity: 1; }
}
チェックされるタブが変わる度に再生するアニメーションも切り替えることで、タブを切り替える度にアニメーションが再生されるようになりましたね:D!

スライドショー