通常タブ切り替えはJavaScriptを使って実装するケースが多いですが、実は CSSだけ でも作れます。
この記事では、:checked
疑似クラスや :has()
擬似クラスを活用して、シンプルかつ軽量なタブ切り替えを実装する方法を紹介します。
「HTMLとCSSの基礎が分かる方」を対象としていますが、サンプルコードをそのままコピペすれば 初心者でもすぐ使える ようになっています。
- 実装例:当サイトトップページ

「新着記事」と「更新記事」の切り替えに使っています。
CSSだけで実現!タブ切り替えの実装方法
ここでは次の2つの方法を紹介します。
- :checked版 → ブラウザ対応が広く、実用向き
- :has版 → モダンな書き方でスッキリ
項目 | :checked版 | :has版 |
---|---|---|
書き方 | input → label → content の順が必須 | 構造の自由度が高い |
コード量 | 少し長い | スッキリ |
ブラウザ対応 | 広い(古い環境でもOK) | モダンブラウザのみ(ほぼすべてに対応) |
実用度 | 高い(商用向け) | 学習・実験向け |
方法① :checked を使う互換性重視版
ラジオボタンと :checked
擬似クラスを活用する方法。古めの環境も含めて幅広く対応するため、使いやすい方法です。
▶ CodePenデモ(:checked版)
See the Pen タブ切り替え|基本スタイル by Turicco (@Turicco) on CodePen.
<div class="tab-switch">
<input type="radio" id="tab1" name="TAB" checked>
<label for="tab1">タブ①</label>
<div class="tab-content">タブ①の内容</div>
<input type="radio" id="tab2" name="TAB">
<label for="tab2">タブ②</label>
<div class="tab-content">タブ②の内容</div>
<input type="radio" id="tab3" name="TAB">
<label for="tab3">タブ③</label>
<div class="tab-content">タブ③の内容</div>
</div>
.tab-switch {
--tab-color:#92bac2;
display: flex;
flex-wrap: wrap;
max-width: 800px;
margin-inline: auto;
gap: 0 5px;
}
/* ラジオ非表示 */
.tab-switch input {
display: none;
}
/* タブボタン */
.tab-switch label {
padding: 0.7em 1em;
background:#eee;
cursor: pointer;
order: -1;
text-align: center;
}
/* コンテンツ非表示 */
.tab-content {
display: none;
width: 100%;
padding: 1.5em 0;
}
/* 選択されたタブ+コンテンツ表示 */
.tab-switch input:checked + label {
background: var(--tab-color);
color: #fff;
}
.tab-switch input:checked + label + .tab-content {
display: block;
}
HTML記述のポイント
- ラベルとラジオの紐づけ
→for="tab1"
とid="tab1"
を対応させることで、ラベルをクリックするとラジオが切り替わります。
<!-- タブ① -->
<input type="radio" id="tab1" name="TAB" checked>
<label for="tab1">タブ①</label>
<!-- タブ② -->
<input type="radio" id="tab2" name="TAB">
<label for="tab2">タブ②</label>
<!-- タブ③ -->
<input type="radio" id="tab3" name="TAB">
<label for="tab3">タブ③</label>
CSSのポイント
- ラジオボタンを非表示
→ ボタンそのものは見せずに、label
をタブとしてデザイン。
.tab-switch input {
display: none;
}
- 選択中のタブを強調
→:checked
状態の直後にあるラベルを装飾。
.tab-switch input:checked + label {
background: var(--tab-color);
color: #fff;
}
- 選択中のコンテンツを表示
→ 選択中のラベルの直後にある.tab-content
だけ表示されます。
.tab-switch input:checked + label + .tab-content {
display: block;
}
方法② :has() を使うシンプル実装(モダンブラウザ向け)
2023年以降多くのブラウザで :has()
が利用可能になり、さらに直感的に書けるようになりました。
▶ CodePenデモ(:has版)
See the Pen タブ切り替え|外枠付き by Turicco (@Turicco) on CodePen.
<div class="tab-switch">
<label><input type="radio" name="TAB" checked>タブ①</label>
<div class="tab-content">タブ①の内容</div>
<label><input type="radio" name="TAB">タブ②</label>
<div class="tab-content">タブ②の内容</div>
<label><input type="radio" name="TAB">タブ③</label>
<div class="tab-content">タブ③の内容</div>
</div>
.tab-switch {
--tab-color:#dbb6a2;
display: flex;
flex-wrap: wrap;
max-width: 800px;
margin-inline: auto;
gap: 5px;
}
/* タブボタン */
.tab-switch label {
padding: 0.7em 1em;
background:#eee;
cursor: pointer;
order: -1; /* 上に表示 */
text-align: center;
}
/* ラジオ非表示 */
.tab-switch input {
display: none;
}
/* コンテンツ非表示 */
.tab-content {
display: none;
width: 100%;
padding: 1.5em 0;
}
/* 選択されたタブ+コンテンツ表示 */
.tab-switch label:has(:checked) {
background: var(--tab-color);
color: #fff;
}
.tab-switch label:has(:checked) + .tab-content {
display: block;
}
HTML記述のポイント
- ラジオボタンをラベル内に書く
→ ラベルをクリックするとinput
が切り替わり、同時にCSSで状態を判定できます。
<label><input type="radio" name="TAB" checked>タブ①</label>
CSSのポイント
:has(:checked)
で選択状態を判定
→label
の中に:checked
な input がある場合のみ、スタイルを適用。
.tab-switch label:has(:checked) {
background: var(--tab-color);
color: #fff;
}
- 隣接するコンテンツを表示
→ 選択されたラベルのすぐ後ろにある.tab-content
を表示します。
.tab-switch label:has(:checked) + .tab-content {
display: block;
}
タブのスタイル|カスタマイズ例
タブ切り替えは「中身の切り替え」だけでなく、デザインを工夫することで見やすさ・使いやすさがアップします。
ここでは簡単に試せるカスタマイズ例を紹介します。
タブ均等幅
タブを横並びにして、均等に幅を分けたいときは flex: 1 1 auto;
を指定します。項目数が変わっても自動で幅が調整されるので便利です。
See the Pen タブ切り替え|input表示バージョン by Turicco (@Turicco) on CodePen.
.tab-switch label {
flex: 1 1 auto; /* 均等幅 */
}
吹き出し風スタイル
選択中のタブに下向きの小さな三角形を付けて、吹き出し風に見せられます。
「今どのタブを選んでいるのか」を直感的に伝えられるデザイン。特にブログ記事の切り替えメニューなどにおすすめです。
See the Pen タブ切り替え|吹き出し風 by Turicco (@Turicco) on CodePen.
.tab-switch label {
position: relative;
}
/* 吹き出し */
.tab-switch label:has(:checked)::before {
content: '';
position: absolute;
top: calc(100% - 1px);
left: 50%;
transform: translateX(-50%);
width: 18px;
height: 9px;
background-color: var(--tab-color);
clip-path: polygon(0 0, 100% 0, 50% 100%);
}
丸・白抜きスタイル
タブをボタン風にしたい場合は、丸みをつけた白抜きデザインがおすすめです。
See the Pen タブ切り替え|丸み by Turicco (@Turicco) on CodePen.
.tab-switch label {
border: 1px solid var(--tab-color); /* 枠線 */
border-radius: 30px; /* 丸み */
}
枠線の色を var(--tab-color)
にしておけば、サイト全体のテーマカラーに合わせて統一感を出せます。
タブ切り替えを 同ページに複数セット置く場合
タブ切り替えを 1ページに複数セット置く場合 は、いくつか注意点があります。
- ラジオボタンの
name
属性はグループごとに固有にする- ラジオボタンは 同じ name を持つと1つしか選べない 特性があります。
- 1つのタブセットごとに違う名前にする必要があります。
<!-- タブセット1 -->
<input type="radio" name="TAB1" id="tab1-1" checked>
<input type="radio" name="TAB1" id="tab1-2">
<!-- タブセット2 -->
<input type="radio" name="TAB2" id="tab2-1" checked>
<input type="radio" name="TAB2" id="tab2-2">
id
とfor
属性も重複させない<label for="id名">
は対応する<input>
と結びつきます。- ページ内で同じ
id
を複数使うと正しく動作しないので、タブセットごと別のid
を付けます。
Cocoonの「タブ」ブロックと活用例
WordPressテーマ「Cocoon」では、バージョン2.7.3以降から直感的に使える便利な「タブ」ブロックが追加されました。この機能を使えば、HTMLコードを書かずにタブ切り替えを実装でき、編集画面でそのまま内容を操作できます。
- 直感的な操作:ブロック内で簡単に編集可能
- レスポンシブ対応:スマホ・タブレットでも快適
当サイトでは、タブのデザインをワンクリックで切り替えられるおしゃれなカスタマイズ方法を紹介しています。
また、Cocoonを使ったサイト型トップページの実装例も公開中です。こちらでは、HTMLとCSSのみでシンプルかつ機能的なタブ切り替えを取り入れ、テーマSWELL風のデザインに仕上げています。
まとめ
HTMLとCSSだけで、シンプルかつ機能的なタブ切り替えを実装できました。
:checked
方式 → 互換性が高く、古いブラウザでも動作:has()
方式 → より直感的に書けるが、モダンブラウザ向け
どちらもJavaScript不要で実装できるので、環境や目的に応じて使い分けましょう。
Comment 記事の感想を書き込んでいただけると幸いです
返信ありがとうございます。
Cocoonではないのでショートコードは使えないのですが、記事拝見させて頂きました。
色々と試みてみたのですが、結局、素人にはどの要素をいれるとカテゴリーの記事一覧が表示されるのかわからずでした…
もう少し頑張ってみます。
コメント失礼します。
HTMLにある「コンテンツをここに入れる」には何を入れたら良いのでしょうか?
タブ自体は奇麗に表示されていますが、各タブの下にカテゴリーを表示したいのですが、URLなどを入力するようなものではないようですし…
他のサイトも拝見したのですが、ここに何を入れるとカテゴリーや記事が表示されるのかわからず質問させて頂きました。
新着記事や人気記事を表示したいならこちらの記事に書いたショートコード(Cocoon独自のものです)を使いますが、
カテゴリーを表示したいということであれば、トップページの作り方という記事を更新しましたのでこちらが参考になるかと思います^^