1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CSSだけで作れる“ちょっと楽しい”タブUIの実装と応用【初心者向けまとめ】

1
Posted at

CSSだけで作れる“ちょっと楽しい”タブUIの実装と応用
【初心者向けまとめ】

限られた画面スペースで情報をまとめることのできるタブUI、
実は JavaScript を使わずに実装できます。

ラジオボタンと :checked 、疑似クラスを使うことでクリック処理を CSS だけで実現し、
JavaScript なしで動作するタブUIの作り方と、知ると“ちょっと楽しい”
応用テクニックを紹介します。

HTML の仕組み

html
<div class="tabs">
  <input type="radio" name="tab" id="tab1" checked>
  <input type="radio" name="tab" id="tab2">
  <input type="radio" name="tab" id="tab3">

  <div class="tab-labels">
    <label for="tab1">タブ1</label>
    <label for="tab2">タブ2</label>
    <label for="tab3">タブ3</label>
  </div>

  <div class="tab-content">
    <div id="content1" class="content">
      <p>タブ1の内容です。</p>
    </div>
    <div id="content2" class="content">
      <p>タブ2の内容です。</p>
    </div>
    <div id="content3" class="content">
      <p>タブ3の内容です。</p>
    </div>
  </div>
</div>

タブUI1.png

クリックすると対応するinputをチェック状態にします。labelをクリック=ラジオボタンを
押すというHTMLのネイティブ機能を利用します。
このままでは各要素がバラバラなので、CSS で整えます。

CSS の実装

css
.tabs input[type="radio"] {
  display: none;
}

.tab-labels {
  display: flex;
  gap: 0;
  border-bottom: 3px solid #e0e0e0;
}

.tab-labels label {
  padding: 15px 30px;
  cursor: pointer;
  background-color: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  transition: all 0.3s ease;
  user-select: none;
  font-weight: 500;
  color: #666;
}

.tab-labels label:hover {
  color: #333;
}

#tab1:checked ~ .tab-labels label[for="tab1"],
#tab2:checked ~ .tab-labels label[for="tab2"],
#tab3:checked ~ .tab-labels label[for="tab3"] {
  color: #3498db;
  border-bottom-color: #3498db;
}

.content {
  display: none;
  padding: 30px;
  background-color: #fafafa;
  border-radius: 0 0 4px 4px;
  min-height: 150px;
}

#tab1:checked ~ .tab-content #content1,
#tab2:checked ~ .tab-content #content2,
#tab3:checked ~ .tab-content #content3 {
  display: block;
  animation: slideIn 0.4s ease;
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

タブUI2.png

:checked + 兄弟セレクタ(~)の組み合わせを使います。
input → tab-labels → tab-content の順番が重要です、

input が先にあるのは、CSS の兄弟セレクタ(~)が “後ろにある要素”
にしか作用しないため、ラジオボタンより後にラベルやコンテンツを置く必要があります。

inputが先頭にあって初めて兄弟として後続要素を操作できます。

動作の仕組み

  1. ユーザーがラベルをクリック
  2. ラベルの for 属性が、対応するラジオボタンの id と一致
  3. ラジオボタンが自動的にチェック状態になる
  4. CSS の :checked 疑似クラスが反応
  5. 対応するタブコンテンツが表示される

タブUIの様々な応用

1.アイコン付き + 縦型タブ

ちょっと変わった「縦に並ぶタブ」で、ダッシュボードや設定画面に便利です。

html
<div class="tabs vertical">
  <input type="radio" name="vtab" id="vtab1" checked>
  <input type="radio" name="vtab" id="vtab2">
  <input type="radio" name="vtab" id="vtab3">

  <div class="tab-labels">
    <label for="vtab1"><span class="icon">🏠</span>ホーム</label>
    <label for="vtab2"><span class="icon">⚙️</span>設定</label>
    <label for="vtab3"><span class="icon">📊</span>統計</label>
  </div>

  <div class="tab-content">
    <div id="vcontent1" class="content">ホームの内容...</div>
    <div id="vcontent2" class="content">設定の内容...</div>
    <div id="vcontent3" class="content">統計の内容...</div>
  </div>
</div>
css
.tabs.vertical {
  display: flex;
  gap: 30px;
}

.tabs.vertical .tab-labels {
  flex-direction: column;
  border-bottom: none;
  border-right: 2px solid #eee;
  width: 180px;
}

.tabs.vertical .tab-labels label {
  margin: 0;
  margin-bottom: 8px;
  border-radius: 8px 0 0 8px;
  border: 1px solid #ddd;
  border-right: none;
  text-align: right;
  padding: 16px 20px;
  background: #f9f9f9;
  transition: all 0.25s;
}

.tabs.vertical .tab-labels label:hover {
  background: #f0f8ff;
}

.tabs.vertical .tab-labels label .icon {
  margin-right: 12px;
  font-size: 1.3em;
}

#vtab1:checked ~ .tab-labels label[for="vtab1"],
#vtab2:checked ~ .tab-labels label[for="vtab2"],
#vtab3:checked ~ .tab-labels label[for="vtab3"] {
  background: #3498db;
  color: white;
  border-color: #3498db;
  border-right-color: transparent;
  position: relative;
}

.tabs.vertical .tab-content {
  flex: 1;
}

.tabs.vertical .content {
  display: none;
  padding: 24px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background: white;
}

#vtab1:checked ~ .tab-content #vcontent1,
#vtab2:checked ~ .tab-content #vcontent2,
#vtab3:checked ~ .tab-content #vcontent3 {
  display: block;
  animation: fadeInLeft 0.4s ease;
}

@keyframes fadeInLeft {
  from { opacity: 0; transform: translateX(-15px); }
  to   { opacity: 1; transform: translateX(0); }
}

CSSの実装 に追加して使用してください。


2.カード風タブ + ホバーでプレビュー表示

タブをクリックする前から中身をチラ見せできる、遊び心のあるデザイン。

html
<div class="tabs card-style">
  <input type="radio" name="ctab" id="ctab1" checked>
  <input type="radio" name="ctab" id="ctab2">
  <input type="radio" name="ctab" id="ctab3">

  <div class="tab-labels">
    <label for="ctab1" class="tab-card">
      <div class="preview">カード1のプレビュー...</div>
      <span>カード1</span>
    </label>
    <label for="ctab2" class="tab-card">
      <div class="preview">カード2のプレビュー...</div>
      <span>カード2</span>
    </label>
    <label for="ctab3" class="tab-card">
      <div class="preview">カード3のプレビュー...</div>
      <span>カード3</span>
    </label>
  </div>

  <div class="tab-content">
    <div id="ccontent1" class="content">本編カード1...</div>
    <div id="ccontent2" class="content">本編カード2...</div>
    <div id="ccontent3" class="content">本編カード3...</div>
  </div>
</div>
css
.card-style .tab-labels {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.card-style .tab-card {
  width: 220px;
  height: 200px;
  background: #fff;
  border: 2px solid #eee;
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  text-align: center;
  padding-top: 160px;
  box-shadow: 0 4px 10px rgba(0,0,0,0.08);
}

.card-style .tab-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 12px 24px rgba(0,0,0,0.12);
}

.card-style .tab-card:hover .preview {
  opacity: 1;
}

.card-style .preview {
  opacity: 0;
  transition: opacity 0.3s;
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1em;
  padding: 20px;
  text-align: center;
}

.card-style .tab-card span {
  font-weight: bold;
  color: #444;
}

#ctab1:checked ~ .tab-labels label[for="ctab1"],
#ctab2:checked ~ .tab-labels label[for="ctab2"],
#ctab3:checked ~ .tab-labels label[for="ctab3"] {
  border-color: #3498db;
  box-shadow: 0 0 0 4px rgba(52,152,219,0.2);
}

.card-style .content {
  display: none;
  margin-top: 30px;
  padding: 30px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}

#ctab1:checked ~ .tab-content #ccontent1,
#ctab2:checked ~ .tab-content #ccontent2,
#ctab3:checked ~ .tab-content #ccontent3 {
  display: block;
  animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

@keyframes popIn {
  0%   { transform: scale(0.92); opacity: 0; }
  60%  { transform: scale(1.05); }
  100% { transform: scale(1); opacity: 1; }
}
カーソルを合わせると変化します。

CSSの実装 に追加して使用してください。

注意点

ラジオボタンの関係性を保つため、同じ name 属性を持つ必要があります。
これが外れてしまうと複数タブ同時選択できて壊れます。

<!-- OK:同じ name -->
<input type="radio" name="tab" id="tab1" checked>
<input type="radio" name="tab" id="tab2">

<!-- NG:異なる name -->
<input type="radio" name="tab1" id="tab1" checked>
<input type="radio" name="tab2" id="tab2">

まとめ

CSS だけで作るタブ UI は軽量でシンプル、そして保守性も高いのが魅力です。

ラジオボタンと :checked を組み合わせることで、JavaScript を使わずに
クリックによるタブ切り替えを実現できます。

基本構造を理解すれば、縦型タブやカード型タブなど、
デザインを自由にアレンジすることも可能です。

シンプルなタブ UI を実装したい場合は、ぜひ CSS のみの手法を活用してみてください!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?