コピペで完結!タブ切替 #03【下線アニメーション付きタブ】

html/css/js

下線アニメーションでタブ切替実装

アクティブなタブの直下に細い下線(インジケーター)がスッと移動するUIです。クリック/キーボード操作(左右・Home/End)に対応し、横スクロール可能なタブバーでも位置計算がズレないように実装しています。

コードについて 本記事のコードは AI(ChatGPT)による生成をベースに作成・調整しています。ご利用の環境でテストの上ご使用ください。
免責 本コードの利用に伴う不具合・損害について、当サイトは責任を負いません。自己責任にてご利用ください。

デモ

選択中タブの幅・位置を実測し、下線をアニメーションで移動させます。

コードをコピーして使おう!

/* =========================================================
   下線アニメーション — CSS(スコープ&可視性対策)
   このブロックでは、下線インジケーターが確実に「見える」ように
   レイアウトと重なり順を制御します。テーマの上書きを避けるため、
   すべてのセレクタを #tabs-underline-06 でスコープしています。
   ========================================================= */

/* ルート要素:外枠の見た目とはみ出し制御 */
#tabs-underline-06{
  background:#fff; /* 背景を白に */
  border:1px solid var(--border); /* 外枠のボーダー */
  border-radius:12px; /* 角丸でカード風に */
  box-shadow:0 6px 18px rgba(2,8,23,.08); /* うっすら影 */
  overflow:hidden; /* 角丸外へはみ出す子要素を隠す */
}

/* タブバー(インジケーターの基準) */
#tabs-underline-06 .tablist{
  position:relative;           /* ← インジケーターの絶対配置基準にする */
  display:flex;                /* タブを横並びに */
  gap:4px;                     /* タブ間の余白 */
  padding:8px;                 /* タブバーの内側余白 */
  border-bottom:1px solid var(--border); /* 下側にボーダー(下線がここを跨ぐ) */
  overflow-x:auto;             /* タブ数が多い時は横スクロール */
  scrollbar-width:thin;        /* Firefox用のスクロールバー細め */
  background:#fff;             /* 背景白(影響受けにくくする) */
}

/* 下線インジケーター(実体の線) */
#tabs-underline-06 .indicator{
  position:absolute;           /* タブバー内で絶対配置 */
  left:0;                      /* 左基準を0に */
  bottom:-1px;                 /* ← 下ボーダーに重ねるため1px下げる */
  height:3px;                  /* 視認性を上げるため3px */
  width:0;                     /* 初期幅は0。JSで選択タブ幅に更新 */
  background:var(--accent, #0b6bff); /* 強調色(アクセント)。フォールバック付 */
  border-radius:2px 2px 0 0;   /* 角を少し丸める */
  transform:translateX(0);     /* X方向の移動はJSでtranslateXを更新 */
  transition:transform .28s ease, width .28s ease; /* スムーズに移動&伸縮 */
  will-change:transform, width;/* ブラウザに最適化ヒント */
  pointer-events:none;         /* クリック等を無効化(操作対象外) */
  z-index:10;                  /* ← タブバーやボーダーより前面に出す */
}

/* タブボタン(共通) */
#tabs-underline-06 .tab{
  appearance:none;             /* ブラウザ標準のボタン外観を無効化 */
  border:none;                 /* 枠線なし */
  background:transparent;      /* 透明背景(選択中のみ背景色) */
  color:var(--muted);          /* 文字色やや淡く */
  padding:10px 14px;           /* クリックしやすいパディング */
  border-radius:8px;           /* 角丸 */
  font-size:14px;              /* 本文相当のサイズ */
  white-space:nowrap;          /* 折り返さない(横スクロール対応) */
  cursor:pointer;              /* クリックできる見た目に */
  line-height:1;               /* 高さを詰めてコンパクトに */
}

/* 選択中タブの見た目(軽いハイライト) */
#tabs-underline-06 .tab[aria-selected="true"]{
  color:var(--ink);            /* 文字色を濃く */
  background:#f8fafc;          /* 背景を薄い面色に */
}

/* フォーカスリング(アクセシビリティ) */
#tabs-underline-06 .tab:focus-visible{
  outline:none;                /* 既定のアウトラインは無効化 */
  box-shadow:0 0 0 3px rgba(11,107,255,.25); /* 青系のフォーカスリング */
}

/* コンテンツパネル領域 */
#tabs-underline-06 .panels{
  padding:16px;                /* 中身の余白 */
  background:#fff;             /* 背景白 */
}

/* 各パネルの表示/アニメーション */
#tabs-underline-06 .panel{
  display:none;                /* まず非表示 */
  animation:tu06Fade .24s ease;/* 表示時にふわっと */
}
#tabs-underline-06 .panel[aria-hidden="false"]{ display:block; } /* 選択時のみ表示 */

/* パネルのフェードイン */
@keyframes tu06Fade{
  from{opacity:0; transform:translateY(4px)} /* うっすら下から */
  to  {opacity:1; transform:translateY(0)}   /* 通常位置に */
}

/* モバイル時の微調整 */
@media (max-width:520px){
  #tabs-underline-06 .tab{ padding:10px 12px; font-size:13px; } /* タブを少し小さく */
  #tabs-underline-06 .panels{ padding:14px; }                   /* 余白も微調整 */
}

コメント