Tailwind CSSで管理画面レイアウトを作る方法|固定ヘッダー・サイドバー開閉・スクロール領域まで

Tailwind CSSで作る管理画面レイアウトの完成イメージ。固定ヘッダー・固定サイドバー・メインだけがスクロールするアプリシェル構成
  • このエントリーをはてなブックマークに追加

スポンサーリンク

Tailwind CSS で管理画面やダッシュボードを作ろうとして、「ヘッダーを固定したいのにスクロールで消える」「サイドバーとメインのスクロールがうまく分かれない」「スマホでサイドバーをどう畳めばいいのか分からない」——こんなところで手が止まっていませんか? 一見むずかしそうな管理画面のレイアウトも、Tailwind の flexoverflow の組み合わせだけで、驚くほどシンプルに組めます。

この記事では、ヘッダーを画面上部に固定し、メインコンテンツだけがスクロールする「アプリシェル」型の管理画面レイアウトを、STEP を追って作っていきます。最後にはスマホでサイドバーをスライドインで開閉するところまで仕上げます。まずは完成形のイメージを見てください。

Tailwind CSSで作る管理画面レイアウトの完成イメージ。固定ヘッダー・固定サイドバー・メインだけがスクロールするアプリシェル構成
これから作る管理画面レイアウトの完成イメージ。ヘッダーとサイドバーは固定され、メインだけがスクロールする

完成形のコードを先に見せます

細かい解説の前に、まず全体像です。上にヘッダー・左にサイドバー・残りがメインという、管理画面でおなじみのレイアウトは、次のコードで作れます。ポイントになるクラスだけコメントを付けました。

<!-- 画面の高さに固定し、はみ出しを止める(全体はスクロールさせない) -->
<div class="h-screen flex flex-col overflow-hidden">

  <!-- ヘッダー:高さ固定。ここは常に見えたまま -->
  <header class="h-14 shrink-0 flex items-center px-4 bg-slate-800 text-white">
    管理画面
  </header>

  <!-- 本体:サイドバー+メインを横並び。残りの高さを埋める -->
  <div class="flex flex-1 overflow-hidden">

    <!-- サイドバー:幅固定・中身が多ければここだけ縦スクロール -->
    <aside class="hidden md:block w-60 shrink-0 overflow-y-auto border-r border-slate-200 bg-slate-50 p-4">
      サイドバー
    </aside>

    <!-- メイン:残り全部・ここだけがスクロールする -->
    <main class="flex-1 overflow-y-auto p-6">
      メインコンテンツ
    </main>

  </div>
</div>

たったこれだけです。ヘッダーは常に上に固定され、中身が長くなってもメインだけがスクロールします。なぜこの書き方で固定とスクロールが両立するのか、一つずつ分解して見ていきましょう。Tailwind の flex の基本があいまいな方は、先にTailwind CSSの使い方【初心者向け】で土台を押さえておくと、この記事がぐっと読みやすくなります。

STEP1:全体を「縦に積む」骨組みを作る

まずは一番外側の枠です。ヘッダー・本体・(必要ならフッター)を縦に積むので、flex flex-col を使います。そして高さを h-screen で画面ぴったりに固定し、overflow-hidden で全体のスクロールを止めるのがミソです。

<div class="h-screen flex flex-col overflow-hidden">
  <header class="h-14 shrink-0 ...">ヘッダー</header>
  <div class="flex flex-1 overflow-hidden">本体</div>
</div>

ここで大事なのが h-screen(=height: 100vh)と overflow-hidden の組み合わせです。「画面の高さでピタッと止めて、外側はスクロールさせない」と宣言しているわけですね。ヘッダーには h-14 shrink-0 を付けて、高さを固定+縮まないようにします。shrink-0 を忘れると、メインの中身が増えたときにヘッダーが押しつぶされてしまうので要注意です。本体の <div>flex-1 で「ヘッダーを引いた残りの高さ」を全部もらいます。

STEP2:サイドバーとメインを横に並べる

次に本体の中を、サイドバーとメインの横並びにします。こちらも flex です。縦に積んだ中を、さらに横に分けるイメージですね。

<div class="flex flex-1 overflow-hidden">
  <aside class="w-60 shrink-0 overflow-y-auto ...">サイドバー</aside>
  <main  class="flex-1 overflow-y-auto p-6">メイン</main>
</div>

サイドバーは w-60 shrink-0幅を固定・縮ませない、メインは flex-1残り全部。ここまではハブ記事と同じ発想です。この記事の肝は、両方に付けた overflow-y-auto です。親の <div>overflow-hidden で高さを固定しているおかげで、サイドバーとメインは「その中だけで」独立してスクロールします。メインを下までスクロールしても、ヘッダーとサイドバーは動きません。これがまさに管理画面らしい挙動です。

「全体スクロール」と「メインだけスクロール」はどう違う?

ここで一度、レイアウトの2つの型を整理しておきましょう。ヘッダーを固定する方法には、大きく2パターンあります。

ページ全体がスクロールするパターンAと、メインだけがスクロールするアプリシェル型パターンBの比較図
ヘッダー固定の2パターン。管理画面はメインだけがスクロールするパターンBが向いている
  • パターンA:ページ全体がスクロールし、ヘッダーだけ追従sticky top-0)。普通のWebサイトやLPに向く。実装が手軽
  • パターンB:画面を固定し、メインの中だけスクロールh-screen overflow-hidden + 各領域に overflow-y-auto)。管理画面・ダッシュボードに向く

この記事で作っているのはパターンBです。「ヘッダーとサイドバーは常に見えていて、データの一覧だけがスクロールする」という、アプリらしいUIになります。もし普通の記事ページのようにページ全体をスクロールさせたいだけなら、パターンAで十分です。その場合はヘッダーに sticky top-0 z-30 を付けるだけで、スクロールしても上に貼り付きます。

<!-- パターンA:ページ全体がスクロールし、ヘッダーが追従する -->
<div class="min-h-screen">
  <header class="sticky top-0 z-30 h-14 bg-slate-800 text-white">ヘッダー</header>
  <main class="p-6">長いコンテンツ...</main>
</div>

sticky は「スクロールの親(スクロールする領域)」を基準に貼り付きます。パターンAでは <div>min-h-screen にして全体をスクロールさせているので、ヘッダーが画面上部に留まります。逆にパターンBのように親を overflow-hidden で固定すると sticky は効きません。「どこがスクロールするのか」で sticky が効くかどうかが決まる——ここを押さえておくと、”貼り付かない” トラブルの大半は避けられます。

STEP3:スマホでサイドバーを開閉できるようにする

PCでは常に表示でいいサイドバーも、スマホでは画面を圧迫します。そこでスマホでは隠しておき、ハンバーガーボタンでスライドインさせるのが定番です。まずサイドバーを、狭い画面では画面外に置いて、開いたときだけ滑り込ませます。

スマホでハンバーガーボタンをタップするとサイドバーが左からスライドインする動きの図解
スマホではサイドバーを画面外に逃がし、ハンバーガーボタンでスライドインさせる
<!-- スマホ:画面外(-translate-x-full)に置き、開いたら 0 に。md以上は常に定位置 -->
<aside id="sidebar"
  class="fixed inset-y-0 left-0 z-40 w-60 -translate-x-full transition-transform duration-200
         overflow-y-auto bg-slate-50 border-r border-slate-200 p-4
         md:static md:translate-x-0 md:z-auto">
  サイドバー
</aside>

<!-- 背景の暗幕(開いているときだけ表示。タップで閉じる) -->
<div id="backdrop" class="fixed inset-0 z-30 hidden bg-black/50 md:hidden"></div>

要点は3つです。fixed inset-y-0 left-0 でサイドバーを画面左端に重ね、-translate-x-fullふだんは左の画面外に逃がしておきます。transition-transform を付けているので、位置が変わるときにスッと滑らかに動きます。そして md:static md:translate-x-0 で、PC(md以上)では重ねずに元の定位置に戻す——これでスマホとPCを1つのマークアップで両立できます。あとは開閉に合わせて -translate-x-full を付け外しするだけです。最小限のJavaScriptで書くとこうなります。

<!-- ヘッダー内のハンバーガーボタン(スマホだけ表示) -->
<button id="menuBtn" class="md:hidden mr-3 text-white">☰</button>

<script>
  const sidebar  = document.getElementById('sidebar')
  const backdrop = document.getElementById('backdrop')
  const toggle = () => {
    // 開閉のたびに位置と暗幕を切り替える
    sidebar.classList.toggle('-translate-x-full')
    backdrop.classList.toggle('hidden')
  }
  document.getElementById('menuBtn').addEventListener('click', toggle)
  backdrop.addEventListener('click', toggle) // 暗幕タップで閉じる
</script>

classList.toggle('-translate-x-full') で「画面外 ⇄ 定位置」を切り替え、暗幕の hidden も同時に付け外しするだけ。ライブラリなしでも十分実用的です。React や Vue、あるいは Alpine.js を使うなら、-translate-x-full の付与を状態(isOpen など)にひも付ければ、同じことがもっと宣言的に書けます。

JavaScriptなしで開閉したいなら peer が使える

「JSを増やしたくない」という場合は、隠しチェックボックスと peer を組み合わせると、CSSだけで開閉できます。チェックボックスのON/OFFを、後ろにある兄弟要素のスタイルに反映させるテクニックです。

<!-- 状態を持つチェックボックス(画面には出さない) -->
<input type="checkbox" id="nav" class="peer hidden">

<!-- ラベルがハンバーガーボタンの役割(クリックでON/OFF) -->
<label for="nav" class="md:hidden cursor-pointer text-white">☰</label>

<!-- peer-checked で「開いた状態」のスタイルを当てる -->
<aside class="fixed inset-y-0 left-0 z-40 w-60 -translate-x-full transition-transform
              peer-checked:translate-x-0 md:static md:translate-x-0">
  サイドバー
</aside>

peer-checked:translate-x-0 は「チェックが入ったら定位置に出す」という意味です。peer前に置いた兄弟要素の状態を参照する仕組み(CSSの後方兄弟セレクタ)なので、チェックボックスはスタイルを当てる要素より前に置く必要があります。この peergroup の使い分けは、Tailwind CSSのpeerとは?groupとの違いで詳しく解説しているので、あわせて読むと応用が効きます。手軽ですが、複雑な開閉制御が必要ならJSのほうが素直です。用途で使い分けましょう。

よくあるつまずきと対処

管理画面レイアウトで「あれ、思ったとおりにならない」となりやすいポイントと、その原因をまとめておきます。ほとんどが overflow と高さ指定の食い違いです。

  • スクロールバーが二重に出る:外側にも overflow-y-auto が付いているのが原因。スクロールさせたいのはメインだけ。外側の枠は overflow-hidden にして、スクロールは <main> に一本化します。
  • メインがスクロールせず、ページごと伸びる:親のどこかで高さが確定していない可能性大。一番外を h-screen、本体の <div>flex-1 overflow-hidden にして、高さを上から下まで伝えます。
  • sticky ヘッダーが貼り付かない:親が overflow-hiddenoverflow-auto だと sticky はそのスクロール領域基準になります。ページ全体で追従させたいなら、overflow を付けた祖先を挟まないようにします。
  • スマホでサイドバーが本文に重ならない/背景を押せてしまう:開いたサイドバーは z-40、暗幕は z-30 のように重なり順(z-index)を明示し、暗幕で背面の操作をブロックします。

迷ったら「スクロールする箱はどれか?」を先に決めるのがコツです。それが決まれば、そこにだけ overflow-y-auto を付け、他は高さを固定する——という単純な話に落ち着きます。

まとめ:管理画面レイアウトはflexとoverflowの組み合わせ

Tailwind CSS の管理画面レイアウトは、覚えることを絞ればとてもシンプルです。最後に要点を振り返っておきましょう。

  • 一番外は h-screen flex flex-col overflow-hidden画面に固定して全体スクロールを止める
  • ヘッダーは h-14 shrink-0高さ固定・縮ませない
  • 本体は flex flex-1 overflow-hidden、その中でサイドバー(w-60 shrink-0)とメイン(flex-1)を横並び
  • スクロールさせたい領域にだけ overflow-y-auto を付ける
  • スマホは fixed -translate-x-fullmd:static md:translate-x-01つのマークアップのままスライドイン開閉

「固定したいものは高さを固定し、スクロールさせたいものにだけ overflow を付ける」。この原則さえ掴めば、どんな管理画面レイアウトも同じ発想で組めます。まずは完成形コードをコピペして、自分のプロジェクトで動かしてみてください。Tailwind の基礎からおさらいしたい方はTailwind CSSの使い方【初心者向け】、入れ子のホバー表現はTailwind CSSのgroup-hover完全解説、フォーム部品の整え方はTailwind CSSでフォームを綺麗に作る方法もあわせてどうぞ。

スポンサーリンク

  • このエントリーをはてなブックマークに追加