会員ログイン
レイアウト

Flexboxでサイドバーを自然に止める方法|align-items: stretchとstickyを解説

FlexboxとCSS Gridでmainとsidebarの高さを合わせ、sticky要素が親要素の終端で止まる仕組みを示した図
はじめに
概要
※本記事の情報は執筆時点のものです。ソフトウェアやサービスの仕様は変更される場合があるため、実際の画面や公式情報も合わせてご確認ください。

この記事では、mainコンテンツとサイドバーの文章量が違っても、追従する要素がちょうどよい位置で止まる仕組みを解説します。ポイントは、Flexboxのalign-items: stretch;で左右を高い側へ揃えること、伸びたサイドバーの子要素へposition: sticky;を指定すること、祖先要素のoverflowを確認することの3つです。当サイトで使用しているCSS Grid版も後半で紹介します。

※本記事の情報は2026年8月執筆時点のものです。ブラウザやテーマのHTML構造によって表示が異なる場合があります。
疑問を持つ読者のイラスト読者

mainの記事は長く、サイドバーは短いのに、目次がちょうどよい位置で止まるのはなぜですか?

著者・木村のプロフィール写真木村

Flexboxならalign-items: stretch;で外側のサイドバーをmainと同じ高さまで伸ばし、その子要素の目次だけをposition: sticky;で追従させます。

話を聞く読者のイラスト読者

JavaScriptでmainの高さを取得して、サイドバーへ設定しているのではないんですか?

著者・木村のプロフィール写真木村

現在の当サイトでは、高さの計算にJavaScriptを使っていません。CSS Gridが左右の範囲を作り、stickyが親要素の終端を判断します。

疑問を持つ読者のイラスト読者

それなら、記事の長さが変わってもコードを修正しなくてよいのでしょうか?

著者・木村のプロフィール写真木村

はい。レイアウト後の高さに合わせてブラウザが処理するため、文章量が変わっても自動で調整されます。重要なのは外側と内側を分けることです。

先に動画で確認したい方は、こちらをご覧ください。Flexboxのalign-items: stretch;、stickyを子要素へ指定する理由、祖先要素のoverflowを確認するポイントを、実際の動きとあわせて解説しています。

今回の実装で重要な3つのポイント

先に結論を整理します。Flexboxで左右の高さを揃え、伸ばしたサイドバーを追従範囲として使い、その子要素だけをstickyにします。うまく動かない場合は、親だけでなく、さらに上の祖先要素まで確認することが大切です。

align-items: stretchで左右を高い側へ揃える

Flexboxでは、親要素へalign-items: stretch;を指定すると、子要素が交差方向へ伸びます。横並びのレイアウトでは縦方向へ伸びるため、mainの内容が長ければ、短いサイドバーもmainと同じ高さまで広がります。

stretchはFlexboxの初期状態でも働きますが、align-items: start;やサイドバーのalign-self: start;で上書きすると高さは揃いません。この記事では、役割が分かるようにstretchを明示します。

stickyは伸ばしたsidebarの子要素へ指定する

position: sticky;を指定するのは、外側のサイドバーではなく、その中にある目次や人気記事です。外側のサイドバーは「移動できる範囲」、内側の要素は「実際に追従するパーツ」という役割になります。

外側のサイドバーがmainと同じ高さまで伸びているため、子要素はその範囲内を追従し、サイドバーの下端へ到達すると自然に止まります。

overflowは親より上の祖先要素まで確認する

stickyが効かないときは、直接の親だけでなく、その親、さらに上の親まで確認します。途中の祖先要素にoverflow: hidden;autoscrollなどがあると、stickyが基準にするスクロール領域が変わり、画面に対して期待どおり追従しないことがあります。

stickyの指定箇所だけを見ても原因が分からない場合は、開発者ツールで外側へ一つずつたどり、祖先要素すべてのoverflowを確認してください。

Flexboxとstickyのシンプルな実装

実装は、HTMLで役割を分け、Flexboxで左右を揃え、サイドバーの子要素へstickyを指定するだけです。固定の高さやJavaScriptによる計算は使いません。

HTMLを3つの役割に分ける

全体を囲む.layout、長い本文を入れるmain、追従範囲になるasideを用意します。追従させたい目次や人気記事は、asideの子要素として配置します。

<div class="layout">
  <main class="main-content">
    <h1>記事タイトル</h1>
    <p>ここに長さが変わる記事本文が入ります。</p>
  </main>

  <aside class="sidebar">
    <section class="sidebar__sticky">
      <h2>目次または人気記事</h2>
    </section>
  </aside>
</div>

Flexの親へalign-items: stretchを指定する

.layoutをFlexコンテナにし、align-items: stretch;を指定します。mainの文章量が多い場合は、その高さを基準にサイドバーも縦へ伸びます。

.layout {
  display: flex;
  align-items: stretch;
  gap: 42px;
}

.main-content {
  flex: 1 1 auto;
  min-width: 0;
}

.sidebar {
  flex: 0 0 300px;
}

.sidebar__sticky {
  position: sticky;
  top: 24px;
}

top: 24px;は、画面上端から追従させる位置です。固定ヘッダーがある場合は、ヘッダーの高さと余白に合わせて調整してください。

高さを固定しなくても内容に合わせて変わる

mainへ文章や画像を追加するとFlexコンテナが高くなり、サイドバーも自動で同じ高さまで伸びます。height: 2000px;のような固定値は不要です。

実行後は、.sidebar__stickyが指定位置で追従を始め、伸びた.sidebarの終端で止まります。これが、左右の内容量が変わってもちょうどよい位置でスクロールが終了する仕組みです。

当サイトで使用しているCSS

当サイトではCSS Gridを採用し、mainとサイドバーを.content-layoutで横並びにして、外側の.sidebarをGridの行まで伸ばしています。前章のFlexbox版でも同じ追従動作を作れますが、ここでは実際のサイトコードを確認します。

content-layoutとsidebarの役割

実際の基本部分は次のとおりです。.content-layoutalign-items: start;に対し、.sidebarだけがalign-self: stretch;で上書きされます。

.content-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  align-items: start;
  gap: 42px;
}

.sidebar {
  position: static;
  align-self: stretch;
}

.article-toc {
  position: sticky;
  top: 108px;
}

top: 108px;は固定ヘッダーと余白を避けるための値です。自分のサイトへ取り入れる場合は、ヘッダーの高さに合わせて調整してください。

トップページでは人気記事を追従させる

トップページでは、サイドバー内の人気記事セクションへsticky用のクラスを追加しています。プロフィールや検索欄は通常どおり流れ、人気記事が指定位置へ来たときだけ追従します。

記事詳細ページでは目次を追従させる

記事詳細ページでは、人気記事ではなく、その下にある記事内目次へstickyを指定します。記事本文、関連する記事、コメントなどでmainの高さが変わっても、外側のサイドバーが同じGridの行まで伸びるため、目次はその終端で止まります。

stickyそのものの基本は、position: stickyでサイドバーを追従固定する方法で詳しく解説しています。本記事では、その追従範囲がmainの高さに合わせて決まる構造に焦点を当てています。

JavaScriptで高さを計算する方法との違い

mainとサイドバーの高さを合わせる方法には、JavaScriptで要素の高さを取得する方法もあります。ただし、今回のような2列レイアウトとstickyの停止位置であれば、まずFlexboxまたはCSS Gridだけで実装できないかを確認するのがおすすめです。

CSSなら文章量の変化へ自動で対応できる

CSS Gridはレイアウト時に内容の大きさを反映します。記事の追記、画像の追加、関連記事の増減などがあっても、Gridの行とサイドバーの範囲が自動で更新されます。

高さを数値として保存しないため、読み込み時や画面サイズ変更時に再計算するコードも不要です。

既存記事はJavaScript方式を扱っている

当サイトには、メインコンテンツとサイドバーの高さをJavaScriptで動的に調整する記事もあります。そちらはDOMContentLoadedoffsetHeightを使い、高さを数値として取得する方法です。

本記事は重複ではなく、現在のサイトで採用しているCSS中心の実装を説明しています。単純な2列レイアウトなら、コードが少なく変更にも強いCSS方式が使いやすいです。

JavaScriptが必要になる場合

高さの数値を別の処理で利用する場合や、複数の要素を独自条件で連動させる場合はJavaScriptが必要になることがあります。見た目を揃えるだけなのか、取得した高さを処理へ使うのかで判断しましょう。

stickyが効かないときの確認点

うまく追従しない場合は、次の順番で確認すると原因を見つけやすくなります。特に見落としやすいのは、Flexboxの伸び方と、離れた祖先要素に指定されたoverflowです。

align-itemsまたはalign-selfがstretchか

開発者ツールで外側の.sidebarを選び、mainと同じ高さまで伸びているか確認します。Flexの親がalign-items: start;になっていたり、サイドバーへalign-self: start;が指定されていたりすると、サイドバーは内容の高さまでしか伸びません。

追従範囲が短い場合は、Flexの親をalign-items: stretch;に戻すか、サイドバーへalign-self: stretch;を指定します。そしてstickyは、伸ばしたサイドバーの子要素へ付けます。

overflowは祖先要素をすべて確認する

overflow: hidden;が直接の親になくても安心できません。その親より上のラッパーやページ全体を囲む要素に指定されていても、stickyの基準へ影響します。

sticky要素からbodyまで祖先要素を一つずつたどり、overflow: hidden;autoscrollがないか確認します。必要のない指定なら外し、必要な場合はHTML構造やスクロールさせる要素を見直します。

スマホと高さのある目次に対応する

スマホでは横並びを解除し、stickyも通常配置へ戻すと読みやすくなります。目次が画面より高い場合だけ、sticky要素自身に最大高さと内部スクロールを設定します。

.sidebar__sticky {
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}

@media (max-width: 980px) {
  .layout {
    display: block;
  }

  .sidebar__sticky {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

ここでのoverflow-y: auto;は、画面より高いsticky要素の内部だけをスクロールさせる意図があります。祖先要素へ不用意に指定する場合とは役割が異なります。

まとめ

  • Flexboxでmainとサイドバーの高さを揃え、サイドバーの子要素へstickyを指定すると、内容量が変わっても追従要素を自然な位置で止められます。
  • Flexの親へalign-items: stretch;を指定し、左右を高い側へ揃える
  • 外側のsidebarは追従範囲として伸ばし、stickyはその子要素へ指定する
  • 効かない場合はalign-itemsalign-selfを確認する
  • overflow: hidden;は直接の親だけでなく、さらに上の祖先要素まで確認する
  • 高さの固定値やJavaScriptによる計算は基本的に必要ない
  • まずは「外側をstretchで伸ばす」「内側をstickyにする」という2つの役割を分けてください。動かないときは祖先要素を上へたどると、原因を見つけやすくなります。

MEMBER COMMENTS

コメント(2件)

  1. たくや

    align-items: stretchがstickyへ影響するところで詰まっていました。親側をflex-startにする理由まで分かり、手元のレイアウトでも直せました。ありがとうございます。

    1. Souichi_Kimura

      ありがとうございます。解決してよかったです。

会員ログイン後にコメントできます

記事への質問や感想をコメントで共有できます。無料会員登録後もこの記事へ戻れます。