コピペで完結!タブ切替 #09【初期表示を速くするためのタブ】

html/css/js

初期表示を速くするためのタブ(Lazy Loading)

ページを開いた直後から全タブの中身を描画すると、表示が重くなり読込時間も延びてしまいます。 そこで最初は「概要」だけを表示し、他のタブはクリックされた時点で初回のみ読み込む仕組みにすることで、初期表示を大幅に軽くできます。

  • 必要なタイミングだけロードすることで初期表示の高速化
  • 以降はキャッシュを使い、再読み込みの無駄を削減
  • 読み込み中はスピナーを表示し、ユーザー体験を維持
  • <template>data-*属性を利用し、シンプルに実装可能
コードについて 本記事のコードは AI(ChatGPT)による生成をベースに作成・調整しています。ご利用の環境でテストの上ご使用ください。
免責 本コードの利用に伴う不具合・損害について、当サイトは責任を負いません。自己責任にてご利用ください。

デモ

最初に表示されるのは「概要」だけ。他のタブは、クリックされた時点でテンプレートから読み込みます(初回のみ)。

タブ内コンテンツを、初回クリック時に遅延ロードします。読み込み中はスピナーを表示し、完了後は結果をキャッシュします。

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

/* =========================================
   タブ内コンテンツ遅延読み込み(Lazy):CSS
   -----------------------------------------
   ・必要最小限のスタイルで、他スタイルと衝突しないよう
     セレクタは #demo-section 配下に限定しています。
   ========================================= */

/* ルート領域(タイポと色のトークン定義) */
#demo-section.demo-wrap{
  max-width: 960px;                          /* 横幅上限(レイアウトの基準) */
  margin: 0 auto;                            /* コンテンツ中央寄せ */
  padding: 0 16px;                           /* 左右の余白 */
  font-family: system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans JP","Yu Gothic UI",sans-serif; /* 読みやすいフォント */
  color: #0f172a;                            /* 基本文字色 */
  --ink:#0f172a;                              /* 文字色トークン */
  --muted:#64748b;                            /* 補助文字色トークン */
  --accent:#0b6bff;                           /* 強調色トークン */
  --border:#e5e7eb;                           /* 枠線色トークン */
  --panel:#ffffff;                            /* パネル背景トークン */
}

/* タブバー(ボタンを横並び、折返し可) */
#demo-section .tabs{
  display:flex;                               /* 横並び */
  flex-wrap:wrap;                             /* 画面が狭い時は折返し */
  gap:8px;                                    /* ボタン間の余白 */
  padding:8px;                                /* タブバー内側余白 */
  background:#f8fafc;                         /* 下地背景 */
  border:1px solid var(--border);             /* 外枠線 */
  border-radius:12px;                         /* 角丸 */
  margin: 0 0 12px;                           /* 下のパネルとの間隔 */
}

/* タブボタンの見た目 */
#demo-section .tab{
  appearance:none;                            /* OS既定の装飾を解除 */
  border:1px solid var(--border);             /* 薄い枠線 */
  background:#fff;                            /* 背景 */
  color:var(--ink);                           /* 文字色 */
  padding:8px 14px;                           /* クリックしやすい余白 */
  border-radius:10px;                         /* 角丸 */
  font-size:14px;                             /* 文字サイズ */
  cursor:pointer;                             /* ホバー時のカーソル */
  transition:background .2s,color .2s,border-color .2s; /* 色変化を滑らかに */
}

/* 選択中タブ(JSが aria-selected=true を付与) */
#demo-section .tab[aria-selected="true"]{
  background:var(--accent);                   /* 背景を強調色に */
  border-color:var(--accent);                 /* 枠線も強調色 */
  color:#fff;                                 /* 文字は白 */
  font-weight:600;                            /* わずかに太く */
}

/* パネル(コンテンツボックス) */
#demo-section .panel{
  border:1px solid var(--border);             /* 枠線 */
  border-radius:12px;                         /* 角丸 */
  background:var(--panel);                    /* 背景色 */
  padding:16px;                               /* 余白 */
  min-height:160px;                           /* ローディング時の最小高さ確保 */
}

/* ローディング表示(ドット3つの簡易アニメーション) */
#demo-section .loading{
  display:flex; gap:8px; align-items:center; justify-content:center;
  height:120px; color:#475569; font-size:13px;
}
#demo-section .loading .dot{
  width:8px; height:8px; border-radius:999px; background:#94a3b8;
  animation: dBounce 1.2s infinite ease-in-out;
}
#demo-section .loading .dot:nth-child(2){ animation-delay:.15s; }
#demo-section .loading .dot:nth-child(3){ animation-delay:.3s; }

@keyframes dBounce{
  0%, 80%, 100% { transform: scale(0); opacity:.5; }
  40% { transform: scale(1); opacity:1; }
}

コメント