CSSのoverflowとは、中身がボックスからはみ出したときに「そのまま見せる・隠す・スクロールさせる」のどれにするかを決めるプロパティです。 値は visible・hidden・clip・scroll・auto の5つで、書き方そのものは1行ですが、「横スクロールが出ない」「逆にページ全体が横に動いてしまう」「position: sticky が止まらなくなった」といったつまずきが起こりやすいプロパティでもあります。

この記事では、5つの値を同じボックスに当てて実測した早見表、overflow-x と overflow-y を片方だけ visible にできない仕様の再現、横スクロールの原因を5種類に分けた切り分け手順、原因の要素を見つける確認用コードをまとめました。数値はすべて Chromium 141(Playwright 1.56)で実際に測ったものです。コードはそのまま貼って使える形にしています。

overflowの早見表

幅200px・高さ100px(枠線1px、box-sizing: border-box)の箱に、400×300pxの中身を入れて比べた結果です。

値 はみ出した部分 スクロールバー ユーザー操作でスクロール JSでスクロール(scrollLeft) 主な用途
visible(初期値) そのまま見える 出ない できない できない(0のまま) 通常の表示
hidden 隠れる 出ない できない できる(50に変わる) はみ出しを隠す、角丸の切り抜き
clip 隠れる 出ない できない できない(0のまま) 隠すだけでよいとき、stickyと併用
scroll 隠れる 常に出る できる できる バーの場所を常に確保したいとき
auto 隠れる はみ出したときだけ出る できる できる スクロール領域の基本形

やりたいことから選ぶ場合は次の表が便利です。

やりたいこと 書き方
はみ出した部分を隠したい overflow: hidden;
隠したいが、stickyや片方向のはみ出しは残したい overflow: clip; または overflow-x: clip;
必要なときだけスクロールバーを出したい overflow: auto;
横方向だけスクロールさせたい overflow-x: auto; + 中身を折り返さない指定
1行で末尾を「…」にしたい white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
スクロールバーの出入りで幅が動くのを防ぎたい scrollbar-gutter: stable;
モーダル内のスクロールを背面に伝えたくない overscroll-behavior: contain;
ページ全体の意図しない横スクロールを直したい 「原因の要素を見つける確認用コード」で特定してから直す

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CSS overflow使い方|hidden・scroll・auto効かない原因」

検証した環境

項目 内容
ブラウザ Chromium 141.0.7390.37(Playwright 1.56.0 から起動)
画面サイズ 800×600px(スマホ用コードは 375×667px、タッチ有効)
スクロールバー 幅を取る従来型(15px)と、幅を取らないオーバーレイ型の両方で測定
未実行のもの Safari(iOS・macOS)と Firefox での表示。この2つは仕様と一般に知られた挙動として記載

スクロールバーには、表示領域の幅を使う「従来型」(Windowsの標準など)と、中身の上に重なって幅を使わない「オーバーレイ型」(スマホやmacOSの標準設定)があります。同じCSSでも結果の数値が変わるため、この記事ではどちらで測ったかを書き添えています。

overflowの基本の書き方

overflow は値を1つ書くと縦横の両方に、2つ書くと「横 縦」の順に当たります。

/* 縦横どちらも同じ値 */
.box { overflow: auto; }

/* 1つ目が横(overflow-x)、2つ目が縦(overflow-y) */
.box { overflow: hidden auto; }

/* 方向ごとに個別に書く */
.box {
  overflow-x: auto;   /* 横 */
  overflow-y: hidden; /* 縦 */
}

/* 書字方向に合わせる論理プロパティ(横書きでは inline が横、block が縦) */
.box {
  overflow-inline: auto;
  overflow-block: hidden;
}

overflow が働くには「はみ出す先の大きさ」が決まっている必要があります。 高さを指定していないブロックは中身に合わせて伸びるので、縦方向にははみ出しが起こらず、overflow-y: auto を書いてもスクロールバーは出ません。縦スクロールにしたい箱には height か max-height を指定します。

.log {
  max-height: 200px;  /* これを超えたぶんがスクロール対象になる */
  overflow-y: auto;
}

5つの値を同じボックスで比べる

次のHTMLをそのまま保存して開くと、5つの値の違いを並べて確認できます。

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<style>
  * { box-sizing: border-box; }
  .box   { width: 200px; height: 100px; border: 1px solid #333; margin: 8px 8px 220px; }
  .inner { width: 400px; height: 300px; background: linear-gradient(#fc0, #f60); }
</style>
</head>
<body>
  <div class="box" style="overflow: visible"><div class="inner"></div></div>
  <div class="box" style="overflow: hidden"><div class="inner"></div></div>
  <div class="box" style="overflow: clip"><div class="inner"></div></div>
  <div class="box" style="overflow: scroll"><div class="inner"></div></div>
  <div class="box" style="overflow: auto"><div class="inner"></div></div>
</body>
</html>

各ボックスに JavaScript で scrollLeft = 50; scrollTop = 40; を代入したあとの値を読み取りました。

実行結果(Chromium 141、従来型スクロールバー):

値 clientWidth×clientHeight scrollWidth×scrollHeight スクロールバーの幅 代入後の scrollLeft / scrollTop
visible 198×98 400×300 0 0 / 0
hidden 198×98 400×300 0 50 / 40
clip 198×98 400×300 0 0 / 0
scroll 183×83 400×300 15 50 / 40
auto 183×83 400×300 15 50 / 40

clientWidth は「枠線とスクロールバーを除いた、中身を表示できる幅」、scrollWidth は「はみ出した分も含めた中身全体の幅」です。scrollWidth が clientWidth より大きければ、その箱の中身は横にはみ出しています。 この2つの比較は、あとで出てくる原因の切り分けでも使います。

hiddenとclipの違い

見た目はどちらも「隠す」ですが、hidden はスクロールできる入れ物(スクロールコンテナ)になり、clip はならないという違いがあります。上の結果でも、hidden は JavaScript から scrollLeft を変えられ、clip は0のままでした。

比べる点 hidden clip
スクロールコンテナになる なる ならない
JSやページ内リンクで中身が動く 動く 動かない
Tabキーで隠れた入力欄に移動したとき 中身がスクロールして表示位置がずれることがある ずれない
新しいブロック整形コンテキストを作る 作る(floatの回り込み解除に使える) 作らない
片方向だけの指定 もう片方が visible なら auto に変わる visible と組み合わせられる
子孫の position: sticky この要素が基準になる 基準にならない(ページのスクロールに付く)
はみ出しの余白 なし overflow-clip-margin で指定できる

hidden を指定した箱の中でフォーカスが隠れた要素に移ると、中身がスクロールして表示がずれることがあります。「隠すだけで、スクロールは一切させたくない」場合は clip が合っています。 一方、float の回り込み解除のように整形コンテキストが必要な場面では hidden か display: flow-root を使います。

scrollとautoの違い

中身が収まっている箱(200×100pxの箱に100×50pxの中身)でも測りました。

実行結果(従来型スクロールバー):

値 中身が収まっているとき 中身がはみ出したとき
scroll clientWidth 183(バーの場所を常に15px確保) clientWidth 183
auto clientWidth 198(バーなし) clientWidth 183(バーが現れて15px狭くなる)

auto は必要なときだけバーが出るので見た目がすっきりします。その代わり、中身が増えてバーが現れた瞬間に表示幅が15px狭くなり、レイアウトが少し動きます。 これを避けたいときは、後述の scrollbar-gutter: stable を足します。オーバーレイ型スクロールバーの環境では、scroll でも auto でもバーの幅は0でした。

overflow-xとoverflow-yは片方だけvisibleにできない

「横ははみ出して見せたいが、縦は隠したい」と考えて次のように書いても、思ったとおりにはなりません。

<div class="box" style="overflow-x: visible; overflow-y: hidden">
  <div class="inner"></div>
</div>

getComputedStyle() で実際に適用された値を読み取った結果です。

書いた指定 適用された overflow-x 適用された overflow-y 横にスクロール
overflow-x: visible; overflow-y: hidden auto hidden できる
overflow-x: hidden; overflow-y: visible hidden auto できる
overflow-x: visible; overflow-y: scroll auto scroll できる
overflow-x: visible; overflow-y: clip visible clip できない(横はそのまま見える)
overflow-x: clip; overflow-y: hidden hidden hidden JSからは動く

片方が visible でも clip でもない値のとき、visible は auto に、clip は hidden に読み替えられます。 これは仕様で決まっている動作で、MDN の overflow のページにも同じ説明があります(今回ページを開いて確認しました)。スクロールコンテナは縦横をまとめて1つの入れ物として扱うため、片方だけ「入れ物の外に見せる」ことができない、と考えると覚えやすいです。

片方向だけ隠したいときの書き方は次のとおりです。

/* 縦だけ隠して、横ははみ出したまま見せる */
.box {
  overflow-x: visible;
  overflow-y: clip;
}

/* 横だけ隠して、縦(ドロップダウンやツールチップ)は見せる */
.nav {
  overflow-x: clip;
  overflow-y: visible;
}

visible と組み合わせられるのは clip だけ、と覚えておくと迷いません。

横スクロールが効かない(出ない)原因と直し方

overflow-x: auto を書いたのに横スクロールにならないときは、そもそも中身が横にはみ出していないことがほとんどです。同じ幅200pxの箱で、4通りの書き方を比べました。

<style>
  .row { width: 200px; border: 1px solid #333; overflow-x: auto; }
</style>

<!-- 1. 何もしない:折り返して収まる -->
<div class="row">
  <span>カード1</span> <span>カード2</span> <span>カード3</span>
  <span>カード4</span> <span>カード5</span> <span>カード6</span>
</div>

<!-- 2. 折り返しを止める -->
<div class="row" style="white-space: nowrap">(中身は同じ)</div>

<!-- 3. flex にして子に width だけ指定 -->
<div class="row" style="display: flex">
  <div style="width: 120px">A</div><div style="width: 120px">B</div><div style="width: 120px">C</div>
</div>

<!-- 4. flex の子を縮ませない -->
<div class="row" style="display: flex">
  <div style="flex: 0 0 120px">A</div><div style="flex: 0 0 120px">B</div><div style="flex: 0 0 120px">C</div>
</div>

実行結果:

番号 書き方 clientWidth scrollWidth 結果
1 指定なし 198 198 2行に折り返して収まる。横スクロールなし
2 white-space: nowrap 198 364 横スクロールになる
3 flex + 子に width: 120px 198 198 子が66pxずつに縮んで収まる。横スクロールなし
4 flex + 子に flex: 0 0 120px 198 360 横スクロールになる

原因1:中身が折り返して収まっている

文字やインライン要素は、幅が足りなければ次の行へ折り返します。折り返せる中身は横にはみ出さないので、スクロールも起こりません。 1行に並べたいなら white-space: nowrap を足します。

原因2:flexの子要素が縮んでいる

flex の子要素は、初期値が flex-shrink: 1(足りなければ縮む)です。width: 120px と書いても、合計が親を超えると均等に縮められます。flex: 0 0 120px(または flex-shrink: 0)で縮まないようにすると、はみ出してスクロールになります。

原因3:スクロールさせたい箱の幅が決まっていない

overflow-x: auto を書いた箱自体が中身に合わせて広がっていると、箱の中でははみ出しが起こりません。display: inline-block や width: max-content、float を指定した箱、あとで説明する「flex の子要素」がこれに当たります。箱に max-width: 100% や min-width: 0 を足して、幅が親に収まるようにします。

原因4:指定する要素が違う

overflow-x: auto は「はみ出す中身」ではなく「それを包む親」に書きます。 表を横スクロールにしたい場合、table 自体ではなく、包む div に指定します。

<div class="table-wrap">
  <table>…</table>
</div>
.table-wrap { overflow-x: auto; max-width: 100%; }
.table-wrap table { min-width: 600px; width: 100%; border-collapse: collapse; }
.table-wrap th, .table-wrap td { white-space: nowrap; padding: 8px; border: 1px solid #ccc; }

幅375pxの画面で測ると、.table-wrap は clientWidth 375・scrollWidth 600 となり、表だけが横に動き、ページ全体の横幅は375pxのまま保たれました。

原因5:親や祖先が先に隠している

スクロールさせたい箱より外側に overflow: hidden があり、そちらで先に切り取られている場合もあります。開発者ツールで親をたどり、overflow が付いている要素を確認します。

横スクロールが出てしまう原因と直し方

今度は逆に、出したくないのにページ全体が横に動く場合です。原因は「画面より幅の広い要素がどこかにある」ことなので、まずその要素を見つけます。

原因の要素を見つける確認用コード

ブラウザの開発者ツールのコンソールに貼って実行します。画面の右端や左端からはみ出している要素を一覧にし、赤い線で囲みます。

(() => {
  const w = document.documentElement.clientWidth;
  const list = [...document.querySelectorAll('body *')].filter(el => {
    const r = el.getBoundingClientRect();
    return r.right > w + 0.5 || r.left < -0.5;
  });
  list.forEach(el => (el.style.outline = '2px solid red'));
  console.table(list.map(el => ({
    要素: el.tagName.toLowerCase() + (el.id ? '#' + el.id : '') +
          (el.className ? '.' + String(el.className).trim().replace(/\s+/g, '.') : ''),
    右端: Math.round(el.getBoundingClientRect().right),
    幅: Math.round(el.getBoundingClientRect().width),
  })));
  console.log('画面の幅:', w, '/ ページ全体の幅:', document.documentElement.scrollWidth);
})();

あとで出てくる width: 100vw の要素を置いたページで実行したところ、次のように原因の要素が1つだけ取り出せました(要点のみ)。

要素: div#hero.hero   右端: 800   幅: 800
画面の幅: 785 / ページ全体の幅: 800

一覧に親子が続けて出てきた場合は、いちばん内側(子孫側)の要素が元の原因であることが多いです。CSSだけで手早く見たいときは、次の1行を一時的に足す方法もあります。

* { outline: 1px solid rgba(255, 0, 0, .4); }

outline は大きさに影響しないので、レイアウトを変えずに全要素の輪郭を見られます。

原因A:flexの子要素が縮めない(min-width: auto)

サイドバーと本文を flex で横に並べ、本文の中に長い1行を持つ pre を入れた例です。

<div style="display: flex; width: 300px">
  <div style="flex: none; width: 80px">side</div>
  <div style="flex: 1">
    <pre style="overflow-x: auto; margin: 0">const veryLongLine = "0123456789…(長い1行)";</pre>
  </div>
</div>

実行結果(直す前と後):

状態 本文側の幅 pre の clientWidth / scrollWidth 親の scrollWidth(親の幅は約300)
直す前(flex: 1 のみ) 905 905 / 905 985(親から大きくはみ出す)
直した後(min-width: 0 を追加) 218 218 / 905 298(親に収まり、pre だけが横スクロール)

flex の子要素は min-width の初期値が auto で、「中身の最小幅より小さくは縮まない」という動きをします。長い1行、折り返さない文字列、大きな画像が中にあると、子要素がその幅まで広がり、親を突き抜けます。pre に overflow-x: auto を書いていても、pre 自身が905pxに広がっているので、はみ出しが起こらずスクロールにもなりません。

/* 直し方:flex の子要素に min-width: 0 */
.main { flex: 1; min-width: 0; }

grid でも同じことが起こります。 grid-template-columns: 80px 1fr では本文側が905pxに広がり、80px minmax(0, 1fr) に変えると220pxに収まりました。1fr は minmax(auto, 1fr) と同じ意味で、最小幅が中身に合わせて決まるためです。

/* 直し方:grid は minmax(0, 1fr) */
.layout { display: grid; grid-template-columns: 80px minmax(0, 1fr); }

原因B:width: 100vw

100vw は「スクロールバーの幅も含めた画面の幅」です。縦スクロールバーが幅を取る環境では、100vw の要素はスクロールバーの分だけ画面より広くなります。

実行結果(800px幅の画面、縦に長いページ、従来型スクロールバー):

指定 要素の幅 表示できる幅(clientWidth) ページ全体の幅(scrollWidth) 横スクロール
width: 100vw 800 785 800 15px分だけ発生
width: 100% 785 785 785 なし

オーバーレイ型スクロールバーの環境(スマホやmacOSの標準設定)では差が0になるため、作っている端末では気づかず、Windows で初めて横スクロールが出る、という形で見つかることがよくあります。全幅にしたいブロック要素は、width: 100% か、幅を指定しないのが確実です。

原因C:そのほかのよくある原因

原因 見分け方 直し方
画像や動画が親より大きい 確認用コードで img が出る img { max-width: 100%; height: auto; }
長いURLや英数字が折り返さない 文字を含む要素が出る overflow-wrap: anywhere;
マイナスのmarginや left: -◯px 左端がマイナスの要素が出る 値を見直す、親に overflow-x: clip
width 固定+padding 幅が親+paddingぶん大きい box-sizing: border-box;
画面外に待機させたメニュー(translateX(100%)) 右端が画面幅より大きい メニューの親か body に overflow-x: clip
white-space: nowrap の付けっぱなし 文字要素が出る 必要な箇所だけに限定する

原因を直すのが基本ですが、画面外に待機させるメニューのように「はみ出すこと自体が意図どおり」の場合は、overflow-x: clip で切り取るのが扱いやすい方法です。次の節で理由を説明します。

overflow: hiddenでposition: stickyが効かなくなる例

横スクロールを止めるために body やラッパーへ overflow-x: hidden を書いたら、ヘッダーの position: sticky が止まらなくなった、というのは定番のつまずきです。4通りの親で、ページを300pxスクロールしたあとのヘッダーの位置を測りました。

<div style="overflow: hidden">  <!-- ここを4通りに変える -->
  <header style="position: sticky; top: 0; height: 40px">ヘッダー</header>
  <div style="height: 1200px"></div>
</div>

実行結果:

親の指定 300pxスクロール後のヘッダーの上端 結果
overflow: hidden -300px 画面外へ流れる(stickyが働かない)
overflow-x: hidden -300px 画面外へ流れる(stickyが働かない)
overflow: clip 0px 画面上端に止まる
overflow-x: clip 0px 画面上端に止まる

position: sticky は「いちばん近いスクロールコンテナ」を基準に止まります。hidden を指定した親はスクロールコンテナになるので、sticky の基準がページからその親に切り替わります。ところが親自体はスクロールしないため、止まる動きが起こりません。overflow-x: hidden だけでも、前の節で見たとおり overflow-y が auto に読み替えられ、同じ結果になります。

clip はスクロールコンテナを作らないので、sticky の基準はページのまま保たれます。 横のはみ出しを切り取りつつ sticky も使いたいときは、次の形にします。

/* 直す前 */
.wrapper { overflow-x: hidden; }

/* 直した後 */
.wrapper { overflow-x: clip; }

sticky が働かない原因はほかにもあります(top の指定漏れ、親の高さなど)。ここでは overflow に関係するものだけを取り上げました。

1行で省略する text-overflow: ellipsis

text-overflow: ellipsis は、overflow が visible 以外で、かつ折り返さない1行のときに働きます。3つをセットで書きます。

.ellipsis {
  width: 200px;           /* 幅が決まっていること */
  white-space: nowrap;    /* 折り返さない */
  overflow: hidden;       /* はみ出しを隠す */
  text-overflow: ellipsis;/* 末尾を … にする */
}

幅200pxに対して中身の scrollWidth は409pxで、末尾が「…」に置き換わりました。flex の子要素に使う場合は、前述の min-width: 0 も合わせて必要です。複数行の省略は line-clamp を使う別の方法になります。

scrollbar-gutterでスクロールバーの場所を確保する

scrollbar-gutter は、スクロールバーが出ていないときも、その場所を空けておくプロパティです。auto で中身が増えたときの「がたつき」を防げます。

.panel {
  overflow: auto;
  scrollbar-gutter: stable;            /* バーの側に常に場所を確保 */
}
.panel-centered {
  overflow: auto;
  scrollbar-gutter: stable both-edges; /* 反対側にも同じ幅を確保(中央がずれない) */
}

中身が収まっている幅200pxの箱で測った結果です(従来型スクロールバー)。

指定 clientWidth 確保された幅 中身の開始位置(左端から)
overflow: auto のみ 198 0 1px
+ scrollbar-gutter: stable 183 15(右) 1px
+ scrollbar-gutter: stable both-edges 168 30(左右15ずつ) 16px
overflow: hidden + stable 183 15(右) 1px

overflow: hidden でも場所が確保される点が便利です。たとえばモーダルを開く間だけページを overflow: hidden にする場合、html { scrollbar-gutter: stable; } を指定しておくと、スクロールバーが消えても本文の幅が変わりません。オーバーレイ型スクロールバーの環境では、もともと幅を取らないので何も確保されません。

overscroll-behaviorでスクロールの連鎖を止める

モーダルやサイドメニューの中を端までスクロールすると、続けて背面のページが動き出します。これを「スクロールチェーン(連鎖)」と呼びます。overscroll-behavior で止められます。

値 動き
auto(初期値) 端まで行くと、外側の要素やページへスクロールが伝わる
contain 外側へ伝えない。端でのバウンドなどその要素内の効果は残る。引っ張って更新やスワイプでの戻る操作も働かなくなる
none 外側へ伝えず、端での効果も出さない
/* モーダルの中身:背面のページへスクロールを伝えない */
.modal-body {
  max-height: 80dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* 横スクロールの列:端で「戻る」スワイプが誤って働くのを防ぐ */
.scroller {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

Chromium 141 では CSS.supports('overscroll-behavior', 'contain') が true を返しました。指で端まで動かしたときの連鎖の有無は、自動テストでは測っていません(未実行)。

スマホ向け横スクロールUIのコピペ用コード

カードを横に並べ、指で滑らせて1枚ずつ止まる列です。JavaScript は使いません。

<div class="scroller" tabindex="0" role="region" aria-label="タスク一覧">
  <div class="card">タスク1</div>
  <div class="card">タスク2</div>
  <div class="card">タスク3</div>
  <div class="card">タスク4</div>
  <div class="card">タスク5</div>
</div>
* { box-sizing: border-box; }

.scroller {
  display: flex;
  gap: 12px;
  padding: 12px 16px;
  overflow-x: auto;                 /* 横スクロール */
  overscroll-behavior-x: contain;   /* 端でページの戻る操作に伝えない */
  scroll-snap-type: x mandatory;    /* カード単位で止める */
  scroll-padding-inline: 16px;      /* 止まる位置を左余白ぶんずらす */
  scrollbar-width: none;            /* スクロールバーを隠す(Firefox・新しめの各ブラウザ) */
}
.scroller::-webkit-scrollbar { display: none; } /* スクロールバーを隠す(WebKit系) */

.scroller > .card {
  flex: 0 0 70%;        /* 縮ませない。次のカードが少し見える幅 */
  max-width: 280px;
  scroll-snap-align: start;
  padding: 16px;
  border: 1px solid #ccc;
  border-radius: 12px;
  background: #fff;
}

実行結果(375×667px、タッチ有効):

測った項目 値
.scroller の clientWidth / scrollWidth 375 / 1280
カード1枚の幅 240px(内側の幅343pxの70%)
ページ全体の scrollWidth 375(ページは横に動かない)
scrollLeft = 200 を代入したあとの位置 252(2枚目の先頭に吸着。240+12)

ポイントは3つです。(1) 子要素を flex: 0 0 ◯ で縮ませない、(2) 次のカードを少し見せて「横に続きがある」と伝える、(3) スクロールバーを隠すときはキーボードでも操作できるよう tabindex="0" を付ける。 スクロールバーを隠すと続きがあることに気づきにくくなるため、(2) は特に大切です。スナップの細かい調整は scroll-snap の話題になるので、ここでは最小限にとどめます。

ブラウザの対応状況(2026年10月時点)

機能 状況 確認方法
overflow(visible / hidden / scroll / auto) Baseline: Widely available(2015年7月から) MDN を開いて確認
overflow: clip Chromium 141 で CSS.supports が true。主要ブラウザはいずれも対応済み(Safari は16から、というのが一般に知られた状況) Chromium は実測、ほかは未実行
overflow-clip-margin Chromium 141 で true。ブラウザにより対応範囲に差がある Chromium は実測、ほかは未実行
scrollbar-gutter Baseline 2024(2024年12月から最新の各ブラウザで利用可) MDN を開いて確認、Chromium は実測
overscroll-behavior MDN の表示は「Limited availability」(2026年10月3日に閲覧)。Chromium 141 では true MDN を開いて確認、Chromium は実測
scrollbar-width: none Chromium 141 で true Chromium は実測、ほかは未実行

scrollbar-gutter や overscroll-behavior は、対応していないブラウザでは単に無視されるだけで、表示が崩れることはありません。足しておいて損のない指定として使えます。

うまくいかないときのチェックリスト

症状 確認すること 直し方
縦スクロールが出ない 箱に高さがあるか height か max-height を指定
横スクロールが出ない scrollWidth > clientWidth か white-space: nowrap、子に flex: 0 0 ◯
横スクロールが出ない 箱自体が広がっていないか 箱に max-width: 100%、flex の子なら min-width: 0
ページ全体が横に動く 確認用コードで要素を特定 原因に応じて min-width: 0、width: 100%、max-width: 100%
overflow-x: visible が効かない もう片方が hidden / auto / scroll か clip と組み合わせる
sticky が止まらない 祖先に hidden / auto / scroll があるか clip に置き換える
ドロップダウンが切れる 祖先に overflow: hidden があるか overflow-x: clip; overflow-y: visible、または親の外に出す
… にならない nowrap・overflow・幅の3点 3つをセットで指定、flex の子は min-width: 0
バーの出入りで幅が動く 従来型スクロールバーか scrollbar-gutter: stable
body の overflow: hidden でスクロールできない 指定が残っていないか モーダルを閉じるときに外す

よくある質問

Q. overflow: hidden と overflow: clip はどちらを使えばよいですか? A. float の回り込み解除や、JavaScript で中身を動かす予定があるなら hidden です。単にはみ出しを隠したいだけなら clip が向いています。clip はスクロールコンテナを作らないので、position: sticky や片方向だけの切り取りと両立できます。

Q. body に overflow-x: hidden を書けば横スクロールは解決しますか? A. 見た目は止まりますが、はみ出した要素はそのまま残り、sticky が働かなくなるなどの副作用が出ることがあります。まず確認用コードで原因の要素を見つけて直し、それでも切り取りが必要なときに overflow-x: clip を使う、という順番がおすすめです。

Q. overflow: auto と scroll はどちらが基本ですか? A. 基本は auto です。必要なときだけバーが出ます。バーの出入りで幅が変わるのが気になる場合は、auto に scrollbar-gutter: stable を足すと、scroll のように場所を確保しつつ、不要なバーは描かれません。

Q. スクロールバーを隠してもスクロールはできますか? A. できます。scrollbar-width: none と ::-webkit-scrollbar { display: none; } はバーの見た目を消すだけで、スクロールの動きは残ります。overflow: hidden は操作によるスクロール自体ができなくなるので、目的に合わせて使い分けます。

まとめ

  • overflow の値は5つ。隠すなら hidden か clip、スクロールさせるなら基本は auto
  • hidden はスクロールコンテナになり、clip はならない。sticky や片方向の切り取りには clip
  • overflow-x と overflow-y は片方だけ visible にできない(auto に読み替えられる)。visible と組めるのは clip だけ
  • 横スクロールが出ないときは scrollWidth > clientWidth を確認し、white-space: nowrap や flex: 0 0 ◯ で中身をはみ出させる
  • ページ全体が横に動くときは確認用コードで要素を特定。flex の子は min-width: 0、grid は minmax(0, 1fr)、全幅は 100vw ではなく 100%
  • scrollbar-gutter: stable でがたつきを防ぎ、overscroll-behavior: contain で連鎖を止める
  • スマホの横スクロール列は、縮ませない子要素+スナップ+次のカードを少し見せるの3点で作る

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CSS overflow使い方|hidden・scroll・auto効かない原因」

株式会社RJCでは、CSSのレイアウトやスクロールの仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?