CSS Gridが画面からはみ出す|1fr・最小幅・長い文字列の直し方

CSS Gridのはみ出しを列・最小幅・長い文字列から直す方法

CSS Gridでカードを2列に並べたのに、長いURLや大きな画像を入れると画面の右側にはみ出してしまう。1frで均等に分けたはずなのに横スクロールが出ると、どの幅を直せばよいか迷いますよね。

このときは、列そのものが広がっているのか、列の中身だけが飛び出しているのかを分けて見ると、修正する場所が見つけやすくなります。この記事では、同じカードの例を使いながら、列の最小幅、長い文字列、画像や固定幅の原因と直し方を整理します。自分の症状に合う箇所を直し、狭い画面でも内容が欠けずに読める状態を目指しましょう。

目次

はみ出しているのは列か、中身か

最初に、カードの背景や枠線と、その中の文字・画像の位置を見比べます。枠線ごと右へ伸びていれば列の幅を、枠線は収まっているのに文字や画像だけが出ていれば中身の幅を疑います。

見えている状態確認する場所対応する修正
カードの枠ごと広がる列の最小幅・子要素の最小幅列の最小幅/子の最小幅
枠内から文字だけが出る長い文字列・改行禁止の指定文字の折り返し
画像や特定の箱だけが出る画像サイズ・固定幅・min-width画像/固定幅の確認
内容が短くても全体が出る列幅の合計・gap・親要素の幅列とgapの合計を確認

表の修正欄から、自分の症状に合う説明へ移動できます。下の図は2種類のはみ出しを示す模式図です。破線は親の右端、緑の枠はカードを表します。

列とカードの枠が広がる状態と、カードの枠は収まって文字だけが外へ出る状態の比較
枠が広がるのか、中身だけが出るのかで、最初に見る指定が変わります。

実際には複数の原因が重なることもあります。列を直したあとに文字だけが残ってはみ出すなら、修正が無意味だったのではなく、次に中身の折り返しを確認する段階です。

display: gridを指定する親がグリッドコンテナー、その直接の子がグリッドアイテムです。基本の書き方を確認したい場合は、Gridの基本:display: grid・列・gapを先に読むと、以下のコードを追いやすくなります。

1frと列の最小幅

frは、利用できる余りの幅を配分する単位です。ただし、1frには中身に応じた最小幅が関わります。「画面の幅を必ず半分にする指定」と考えると、長い文字列が入ったときにつまずきます。

minmax()の外に書いた1frは、minmax(auto, 1fr)に相当します。今回のように各カードが1列ずつを占める例では、改行できない長い文字列が列を縮めにくくする原因になります。詳しい定義はMDNのgrid-template-columnsで確認できます。

カード2枚の練習コード

手元で試す場合は、練習用の新しいフォルダーにindex.htmlとstyle.cssを作ります。次のHTMLをindex.htmlへ、続くCSSをstyle.cssへUTF-8で保存し、index.htmlをブラウザーで開いてください。この例はサーバー不要です。長いURLは表示を確認するための架空の文字列です。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Gridのはみ出しを確認</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="card-grid">
    <article class="card">
      <h2>長い文字列</h2>
      <p>https://example.com/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz</p>
    </article>
    <article class="card">
      <h2>2枚目のカード</h2>
      <p>カードの内容が入ります。</p>
    </article>
  </div>
</body>
</html>
* {
  box-sizing: border-box;
}

body {
  margin: 16px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

.card {
  padding: 16px;
  border: 1px solid #587465;
  background: #e8ede5;
}

.card p {
  margin: 0;
}

この例では、同じ幅にしたい列をrepeat(2, 1fr)で2本作っています。box-sizing: border-boxは、指定した幅に内側の余白や枠線を含めるための指定です。既存サイトへ適用する際は、この練習用CSS全体を貼らず、対象のカードに必要な変更だけを反映してください。

.card-gridと.cardは、この例で付けたクラス名です。既存サイトでは、HTMLにある親と直接の子のクラス名に読み替えます。変更前のCSSを別ファイルや編集履歴へ残し、対象の指定を1か所ずつ変えて確認してください。

列の最小幅を内容任せにせず縮められるようにするには、style.cssにある.card-gridの指定を見直します。置き換えるのはこの1行です。display: gridやgap: 16pxは、そのまま残します。

変更前

grid-template-columns: repeat(2, 1fr);

変更後

grid-template-columns: repeat(2, minmax(0, 1fr));

minmax(0, 1fr)は、列の最小幅を0にし、余った幅を1frずつ配分する指定です。列の幅を常に0にする意味ではありません。この例では、gapを除いた幅を2列で分けられるようにします。

ここで直すのは列の幅です。文字列を折り返す指定は別に必要なことがあります。保存して再読み込みし、カードの枠が収まったかを見てから、文字の状態を確認してください。

子要素のmin-width: 0の指定先

この練習例では、まずどちらか一方の方法から試します。前の章のように親の列幅を変える方法のほかに、列を1frのままにして、子要素の最小幅を見直す方法があります。2つの方法を比べる場合は、先ほどの列指定をrepeat(2, 1fr)へ戻してから、この方法を試してください。

上のHTMLでは、.card-gridの直接の子である.cardにmin-width: 0を書きます。.cardの中にあるpだけへ書いても、同じ対象の修正にはなりません。

style.cssの.cardの{ }内へ、次のmin-width: 0;を追加します。既存の指定を残して追加します。padding・border・backgroundを消す必要はありません。

.card {
  min-width: 0;
}

min-widthの初期値はautoです。グリッドアイテムでは、条件によって内容に基づく最小幅になります。min-width: 0は、カードの幅を0にする指定ではありません。中身が長くても、カード自体は列の幅に合わせて縮められるようにする指定です。条件や例外はMDNのmin-widthで確認できます。

次の図は、CSSを書く相手をHTMLの親子関係で示しています。Aは親の列幅、Bは直接の子の最小幅です。pはさらに内側にあるため、Bの指定先とは異なります。

親のcard-grid、その直接の子card、さらに内側のpを入れ子の枠で示す。Aは親の列にminmax(0, 1fr)、Bは直接の子にmin-width: 0を指定する選択肢
この練習例ではA・Bの一方で枠を直します。pはBの指定先ではありません。

AまたはBを反映してカードの枠が収まったら、文字や画像が枠から出ていないかを確認します。文字だけが出る場合は、次の章の折り返しを追加します。

ただし、.cardにmin-width: 400pxなどを明示している場合は、その指定自体も見直します。列を縮めても、子に指定した400pxが自動で消えるわけではありません。また、Gridを入れ子にしている場合は、はみ出している段の直接の子を確認してください。

列が収まっても長い文字列が出るとき

カードの枠が収まったのにURLや長い英数字だけが出る場合は、文字の折り返しを指定します。この例では、既存の.card pの{ }内へoverflow-wrap: anywhere;を追加します。margin: 0;は残してください。

.card p {
  overflow-wrap: anywhere;
}

anywhereは、通常の改行位置では収まらない長い文字列を、必要なときに途中で折り返せるようにします。日本語の短い文章まで、いつも一文字ずつ改行する指定ではありません。

anywhereは、長い文字列を途中で折り返せることも考慮して、最小幅を決めます。似た値のbreak-wordは、この折り返しを最小幅の計算に含めません。Gridの最小幅も関わる今回の例では、anywhereを使います。詳しい定義はMDNのoverflow-wrapを参照してください。

折り返されない場合は、対象の文字や親要素にwhite-space: nowrapがないか確認します。これは改行を抑える指定なので、折り返してよい文章なら、同じ要素でwhite-space: normalに戻します。MDNのwhite-spaceも参考になります。

.card p {
  white-space: normal;
  overflow-wrap: anywhere;
}

一方、改行や字下げを保ちたいコード欄では、無理に文章と同じ折り返しへ変えず、その欄だけを横スクロールにする方法があります。次の例は.card内のpreに指定します。

.card pre {
  max-width: 100%;
  overflow-x: auto;
}
HOAI Point

ページ全体の横スクロールと、コード欄の中だけの横スクロールは分けて判断しましょう。bodyへoverflow-x: hiddenを付けて見えなくするだけでは、文章や操作部分が欠けたままになることがあります。読める内容を残すことを基準に、折り返すか、その欄でスクロールさせるかを選びます。

画像・固定幅・gapが原因のとき

列や文字の対処だけで収まらない場合は、はみ出している画像・箱、または列と余白の合計を確認します。次の3項目も、当てはまるものだけを見直してください。

画像の表示幅

文字が収まっていて画像だけが出るなら、列の指定をさらに変える前に画像の幅を確認します。.card内の画像なら、次の指定が出発点になります。

.card img {
  display: block;
  max-width: 100%;
  height: auto;
}

max-width: 100%は、画像の表示幅に親の内容幅を上限として設けます。height: autoは幅に応じて高さを調整するための指定です。画像に大きなmin-widthが付いている場合は、それも見直してください。幅の指定同士の違いは、幅・高さの指定とmax-widthの基本で確認できます。

固定幅・最小幅・余白

カードの中にwidth: 600pxの箱があれば、列を300pxにしても、その箱まで自動で300pxになるとは限りません。widthだけでなく、min-width、左右の余白、枠線も確認します。

親に合わせて伸び縮みしてよい箱なら、固定のwidthをautoや100%へ見直します。width: 100%に左右のpaddingを足している場合は、box-sizing: border-boxで、padding(内側の余白)とborder(枠線)を幅に含める方法があります。margin(外側の余白)は、この幅には含まれません。min-widthが上限より大きいと、max-widthだけでは縮められないため、最小幅も一緒に確認してください。

50%の列とgapの合計

grid-template-columns: 50% 50%にgap: 16pxを加えると、親の内容幅の100%に列間の16pxが追加されます。たとえば親の内容幅が320pxなら、各列は160pxです。合計は160+16+160=336pxになり、16pxはみ出します。中身が短くてもはみ出すなら、この組み合わせを確認しましょう。

親の内容幅が320px、gapが16pxの場合、50%の2列は160+16+160=336px。minmax(0, 1fr)の2列は152+16+152=320pxとなり親の幅に収まる
列間の16pxも含めて、親の幅に収めます。

2列を均等に分けたい場合は、先ほどのrepeat(2, minmax(0, 1fr))とgapの組み合わせを使えます。親の内容幅が320pxなら、gapの16pxを引いた304pxを分け、各列は152pxになります。gapをなくして見た目だけを合わせる前に、列とgapを合わせた幅を確認しましょう。

表示確認と修正の完了条件

はみ出しがなくなっても、狭い画面で2列のカードが読みにくければ、列数も見直します。次は、画面幅が600px以下のときに1列へ切り替える例です。style.cssの通常の.card-grid指定より後へ追加します。

@media (max-width: 600px) {
  .card-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

600pxはこの例の切り替え幅です。実際のカードが読みにくくなる幅に合わせて調整してください。条件の書き方はメディアクエリのmax-width・min-widthで確認できます。

CSSを保存してページを再読み込みしたら、ブラウザーの幅を広い状態から狭い状態へ変え、次の3点を確認します。実際に載せる長いURLや画像でも見ておきましょう。

  • カードの枠が親の幅に収まり、ページ全体に不要な横スクロールが出ていない。
  • 文字・画像・リンクが欠けず、内容を最後まで読める。
  • 列数が切り替わる前後でも重なりがなく、必要なコード欄は欄内でスクロールできる。

この3点を満たせたら、その症状の修正は完了です。記事内の指定をすべて追加する必要はありません。まだはみ出す場合は、残っているのが列か中身かをもう一度見分け、対象の要素に別のwidth・min-width・nowrapがないかを確認してください。

変更しても見た目がまったく変わらない場合は、保存したCSSとHTMLの読み込み先、クラス名の一致を確認します。Chromeでは、対象要素を右クリックして「検証」を開き、Styles(スタイル)に書いた指定が現れるか、打ち消し線で上書きされていないかを確認できます。画面の見方はChrome公式のCSS機能リファレンス(日本語)も参照してください。

別の幅で崩れたり、意図しない要素まで変わったりしたら、直前に変えた値を元へ戻し、追加した行だけを削除して保存・再読み込みします。練習コードでは、列をrepeat(2, 1fr)へ戻すか、追加したmin-width: 0;を外すと比較できます。元の指定が分からない場合は、変更前に残したCSSと照合してください。

よくある質問

minmax(0, 1fr)とmin-width: 0は両方必要ですか?

この練習例では、まず一方を試します。親の列を縮めるのが前者、直接の子の最小幅を変えるのが後者です。枠が収まったら、文字や画像が残ってはみ出すかを確認します。すべての指定をまとめて追加する必要はありません。

min-width: 0を親に書いても直りません。どこを見ますか?

この例ではdisplay: gridを指定した.card-gridの直接の子、.cardが対象です。内側のpだけへ書いても対象が違います。入れ子のGridでは、はみ出している段の親子関係を確認してください。

overflow-wrap: anywhereを足しても文字が折り返されません。

対象の文字や親からwhite-space: nowrapが適用されていないかを確認します。折り返してよい文章なら、対象要素をwhite-space: normalへ戻します。変更が反映されない場合は、CSSの読み込み先・クラス名・上書きも確認してください。

横スクロールが消えれば修正完了ですか?

文字・画像・リンクが欠けずに読めることも確認します。overflow-x: hiddenで内容を隠しただけでは完了にしません。広い画面、狭い画面、列数が変わる前後で確認し、別の崩れが出た場合は直前の変更を戻してください。

まとめ

Gridのはみ出しは、列を縮める指定と、中身を収める指定を分けると整理できます。まずはカードの枠線を見て、列ならminmax(0, 1fr)や子のmin-width: 0、文字なら折り返し、画像や固定幅ならその要素のサイズから見直してみましょう。

この記事を書いた人

横畑デザイン事務所代表。Webデザイナー・プログラミング講師として、WordPressを中心としたWebサイトの制作・運用と個別指導に携わっています。実際の制作や指導で培った知識と経験をもとに、Web制作やAI活用について、初心者が迷わず一歩を踏み出せる情報を分かりやすく発信しています。

目次