CSSのFlexboxで画像が縮む|幅を指定しても小さくなる原因と直し方

Flexboxの画像が縮む原因と直し方。画像側の幅を保つ指定先とスマートフォン対応を解説。

Flexboxで画像と文章を横に並べたら、width: 200px;を指定した画像が小さくなってしまった。そんなときは、画像の幅だけでなく、横並びの中で縮小されている要素を確認します。

画像を直接並べているならimgへ、divやaで包んでいるならその親要素へ、縮小を止める指定を加えます。画像を固定した後は、文章の折り返しと狭い画面での並べ方も整えましょう。

この記事では、画像200px・間隔24pxのカードを例に、指定先の見分け方から、長いURLやスマートフォン幅でも崩れにくいCSSまで説明します。

この記事で分かること
  • HTMLの構造から、縮小を止めるCSSの指定先を選ぶ方法
  • widthを指定しても画像が縮む仕組みと再現例
  • 画像を固定した後の文章のはみ出しとスマートフォン対応
  • flex-shrinkを指定しても直らないときの確認点

今の症状に近いところから確認できます。

作業前に、変更するHTML・CSSを別の場所へコピーして控えてください。この記事の.cardなどはサンプルのクラス名です。自分のHTMLと対応させ、関係する部分だけを変更します。

目次

画像の幅を保つCSSの指定先

最初に探すのは、display: flex;を指定した要素の「直接の子」です。直接の子とは、間に別の要素を挟まず、その要素のすぐ内側に書かれている要素を指します。

Flexboxで並べ方や伸び縮みを調整される直接の子を、フレックスアイテムといいます。imgがその対象なのか、画像を包む要素が対象なのかで指定先が変わります。

HTMLの形縮小を止める指定先基本の指定
画像を直接並べるimgwidth: 200px;
flex-shrink: 0;
画像をdivやaで包む画像を包む直接の子flex: 0 0 200px;
display:flexを指定したカードの直接の子がimgの場合と、画像を包むdivの場合。茶色の枠が画像側の指定先。
画像を包む要素がある場合は、その要素の幅を確保します。

imgを直接並べている場合

次のHTMLでは、.cardの直接の子はimg.card__imageとdiv.card__bodyです。画像自体にflex-shrink: 0;を指定します。

HTML

<div class="card">
  <img class="card__image"
       src="images/sample.jpg"
       width="640" height="360"
       alt="山と太陽の風景">
  <div class="card__body">
    <p>画像と文章を横に並べるカードです。</p>
  </div>
</div>

CSS

.card {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.card__image {
  width: 200px;
  height: auto;
  flex-shrink: 0;
}

flex-shrink: 0;は、空き幅が足りないときに、そのフレックスアイテムを縮小しない指定です。height: auto;は画像の縦横比を保つために加えています。

コードのimages/sample.jpgは、自分の画像ファイルへのパスに変えてください。HTMLのwidth・height属性も元画像の寸法に合わせます。この例では640×360pxの画像を、CSSで横幅200pxに表示します。

画像をdivやaで包んでいる場合

画像側で.cardの直接の子になっているのは、.card__mediaです。imgだけにflex-shrink: 0;を加えても、外側の.card__mediaが縮むことは止められません。

HTML

<div class="card">
  <div class="card__media">
    <img src="images/sample.jpg"
         width="640" height="360"
         alt="山と太陽の風景">
  </div>
  <div class="card__body">
    <p>画像と文章を横に並べるカードです。</p>
  </div>
</div>

CSS

.card {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.card__media {
  flex: 0 0 200px;
}

.card__media img {
  display: block;
  width: 100%;
  height: auto;
}

flex: 0 0 200px;は、順に伸びる割合・縮む割合・幅の基準値をまとめた指定です。この横並びでは「余った幅で伸ばさず、足りない幅で縮めず、200pxを基準にする」と読めます。画像はwidth: 100%;で、その枠の幅に合わせます。

画像をリンクのaで包む場合も考え方は同じです。display: flex;を指定した要素の直接の子がaなら、そのaへ幅を確保する指定を加えます。

親と子の役割を整理したい場合は、Flexboxの基本と親・子に指定するプロパティも参照してください。一括指定の各値は、MDNのflexの解説で確認できます。

widthを指定しても画像が縮む理由

横並びのFlexboxでは、画像・文章・間隔などの合計が親の内側の幅に収まらないと、収まりきらない分だけ、縮小できる画像や文章の幅が調整されます。flex-shrinkの初期値は1です。

そのため、width: 200px;は「いつでも実際の表示幅が200pxになる」という保証ではありません。最終的な幅は、flex-basis、伸び縮みの指定、最小幅・最大幅なども含めて決まります。

ただし、幅が足りなければ画像が必ず縮むわけではありません。フレックスアイテムのmin-width: auto;による自動の最小幅が、縮小を止める場合もあります。画像が保たれる代わりに、文章やカード全体がはみ出すこともあります。

200pxの画像が約152pxに縮む例

ここでは縮小の違いを確かめるため、カード幅420px、画像の指定幅200px、文章の指定幅320px、間隔24pxにします。合計544pxなので、124px不足します。

この例では「imgを直接並べている場合」のHTMLを使います。前のCSSに追加せず、この例のCSSへ置き換えて試してください。

CSS(修正前)

/* 縮小を比較するための再現条件 */
.card {
  display: flex;
  width: 420px;
  gap: 24px;
  align-items: flex-start;
}

.card__image {
  display: block;
  width: 200px;
  height: auto;
  min-width: 0;
  flex-shrink: 1;
}

.card__body {
  width: 320px;
  min-width: 0;
}

この例のmin-width: 0;は、自動の最小幅による制限を外して、縮小を再現するための指定です。画像を固定するために必ず加えるものではありません。

同じ420pxのカードで、修正前の画像幅が約152px、flex-shrink:0を指定した修正後は200pxになった表示例。
この記事用の再現例。画像と文章の幅が足りない条件で比較しています。

ブラウザーで実行したところ、画像の表示幅は約152.31pxになりました。画像のflex-shrink: 1;をflex-shrink: 0;へ変更すると200pxを保ち、文章の幅は196pxになります。縮小量は単純な均等割りではなく、縮小率と幅の基準値を使って配分されます。

この数値は上記の再現条件での結果です。画像や文章の内容、余白、ほかのCSSが違えば実際の幅も変わります。

また、画像を包む要素が縮む例では、imgだけを変更しても約152.31pxのままでした。包む要素へflex: 0 0 200px;を指定すると、画像も200pxになりました。

仕組みの詳細は、MDNのflex-shrinkと、min-widthのautoの説明を参照してください。

画像固定後の文章と画面幅の調整

画像の幅が戻ったら、隣の文章と狭い画面を確認します。文章だけがはみ出す場合は折り返し、横並びで文章が読みにくい場合は縦並びへの切り替えを調整しましょう。

長いURLの折り返し

画像を固定できても、隣の長いURLや英数字が横にはみ出すことがあります。次のCSSを追加し、既存の.card__bodyの指定がある場合は置き換えてください。

CSS(文章側に追加・置換)

.card__body {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

flex: 1;は残りの幅を文章側に使わせる指定です。min-width: 0;で文章の枠を狭められるようにし、overflow-wrap: anywhere;で、入りきらない長いURLなどにも途中で折り返せる場所を作ります。

文章の枠を狭める指定と、文字列を折り返す指定はセットで考えます。枠だけを狭めても、折り返せない文字列がその外へはみ出す場合があるためです。

下の図は、文章の枠と、長いURLの英数字部分を取り出した模式図です。白い部分が文章の枠を表します。overflow-wrap: normal;は初期値で、ここでは折り返しの指定を追加していない状態です。

min-width:0だけでは文章の枠から長い英数字がはみ出し、overflow-wrap:anywhereも指定すると枠の中で折り返される比較図。
枠を狭めるだけでは、長い文字列がはみ出す場合があります。

同じ420pxのカードで長いURLを入れた再現例では、画像を200pxに固定しただけでは横にはみ出しました。上の文章側の指定を加えると、画像200px・間隔24px・文章196pxに収まりました。white-space: nowrap;を別のCSSで指定している場合は、それも見直してください。

改行できる条件の詳細は、MDNのoverflow-wrapを参照してください。

HOAI Point

画像の縮小を止めても、足りなかった幅が増えるわけではありません。文章を折り返す、間隔を狭める、縦並びに切り替えるなど、残りの内容が収まる形も一緒に決めましょう。

狭い画面での縦並び

画像200pxと間隔24pxを確保すると、画面が狭いほど文章の幅が減ります。文章が読みづらい幅になったら、画像と文章を縦に並べる方法が使えます。

次のHTMLとCSSが、このカードの完成例です。ここまでの例とは置き換えて使ってください。再現用の420px・320pxという固定幅は外し、カードを親の幅に合わせて最大720pxにします。

HTML

<div class="card">
  <div class="card__media">
    <img src="images/sample.jpg"
         width="640" height="360"
         alt="山と太陽の風景">
  </div>
  <div class="card__body">
    <p>画像と文章を横に並べるカードです。</p>
  </div>
</div>

CSS

.card {
  display: flex;
  width: 100%;
  max-width: 720px;
  gap: 24px;
  align-items: flex-start;
}

.card__media {
  flex: 0 0 200px;
}

.card__media img {
  display: block;
  width: 100%;
  height: auto;
}

.card__body {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

.card__body p {
  margin: 0;
}

@media (max-width: 600px) {
  .card {
    flex-direction: column;
    gap: 16px;
  }

  .card__media {
    flex: 0 1 auto;
    width: 200px;
    max-width: 100%;
  }

  .card__body {
    width: 100%;
  }
}

縦並びへ変えるときは、画像側のflex: 0 0 200px;も解除します。flex-direction: column;では、flex-basisが横幅ではなく縦方向の基準になるからです。

上の例ではflex: 0 1 auto;に戻し、画像の横幅はwidth: 200px;で指定します。さらにmax-width: 100%;で、親が200pxより狭い場合は親の幅に収めます。

画面幅390px相当で、画像と文章が縦に並び、長いURLが文章の幅で折り返されている完成例。
画面幅390pxでの表示例。画像と文章を縦に並べています。

600pxはこのサンプルの切り替え位置です。すべてのサイトに共通する値ではありません。自分の記事やカードの文字量を入れ、横並びの文章が読みにくくなる幅に合わせて調整してください。

CSSを保存してブラウザーを再読み込みしたら、次の3点を確認します。自分の画像・文章に加え、長いURLでも試してください。

  • 広い画面:画像が狙った幅を保ち、文章が隣に収まる。
  • 切り替え位置の前後:この例なら601pxで横並び、600pxで縦並びになり、不自然な空白がない。
  • 狭い画面:画像と文章が親の幅に収まり、ページ全体に横スクロールが出ない。

この3点を満たせば、今回の調整は完了です。別の部分が崩れた場合は、今回変更した箇所を控えた内容へ戻し、保存・再読み込みで元の表示に戻るか確認してください。その後、指定先や競合するCSSを一つずつ調べます。

画面幅でCSSを切り替える構文は、MDNの@mediaで確認できます。

まだ直らないときに確認するCSS

指定先が合っていても、ほかのCSSで幅が制限されることがあります。画像全体が小さいのか、縦横比が崩れているのかを分けて確認します。

幅を制限・上書きするCSS

flex-shrink: 0;を指定しても期待した幅にならない場合は、まずその指定が「縮んでいる直接の子」に付いているかを確かめます。そのうえで、次の指定を探してください。

  • flexやflex-basis:flex: 1;などの一括指定で縮小率や幅の基準が変わっていないか。横並びでflex-basisがauto以外なら、幅の計算ではwidthより優先されます。
  • max-width:200pxより小さい上限や、狭い親を基準にしたmax-width: 100%;が効いていないか。縮小率を0にしても、最大幅の制限は別に残ります。
  • 同じ要素に当たる別のCSS:メディアクエリ内の指定、より優先順位の高いセレクター、!importantなどで上書きされていないか。

開発者ツールを使える場合は、画像とその親をそれぞれ選び、適用中のwidth・flex・min-width・max-widthを比べると指定先を追いやすくなります。むやみに!importantを追加する前に、幅を決めている指定を一つずつ確認しましょう。

MDNのflex-basisと、width・max-widthの違いを解説した記事も確認に使えます。

画像の縦横比と切り抜き

画像の縦横比が変わって横につぶれて見える場合は、幅の縮小に加えて高さの指定も確認します。全体を自然な比率で表示するなら、基本はheight: auto;です。

枠の幅と高さを両方固定して切り抜きたい場合は、object-fit: cover;を使います。ただし、これは画像の内容を枠の中へどう収めるかの指定です。フレックスアイテムの幅を固定する役割はありません。

切り抜きによって画像の一部は見えなくなります。画像全体を見せたいならcontainとの違いも含め、MDNのobject-fitを確認してください。

よくある質問

min-width: 200px;を指定する方法でも直せますか?

最小幅を200pxにすることで、それより小さくなるのを防げます。ただし、親が狭くなっても200px未満になれないため、横にはみ出す場合があります。この記事の例では、伸び縮みと幅の基準をまとめて示せるflexを使い、狭い画面で指定を切り替えています。

flex: none;とflex: 0 0 200px;は何が違いますか?

flex: none;はflex: 0 0 auto;に相当し、Flexboxによる伸び縮みをしません。幅の基準はautoなので、widthなどを参照します。width:200pxと合わせて使う方法もあります。flex:0 0 200pxは、基準の大きさまで200pxとしてまとめて指定する書き方です。

flex-wrap: wrap;で折り返してもよいですか?

はい。空き幅に応じてアイテムを次の行へ送るレイアウトには使えます。ただし、画像と文章がどの幅で別の行へ移るかは、各要素の大きさなどで変わります。一定の画面幅から必ず縦並びにしたい場合は、メディアクエリとflex-direction:columnを使うと意図を明確にできます。

まとめ

Flexboxで画像が縮むときは、まずHTMLの入れ子を見て、どの要素が横並びの直接の子なのかを確かめましょう。

  • imgを直接並べているなら、imgへwidthとflex-shrink:0を指定する。
  • 画像を包む要素がdisplay: flex;を指定した親の直接の子なら、その包む要素へflex: 0 0 200px;などを指定する。
  • 画像を固定した後は、文章側のmin-width:0・overflow-wrap:anywhereと、狭い画面での並べ方も確認する。

最初は自分のHTMLに合う指定先を一つ選び、画像の幅が戻るかを確認してください。その後、長い文章と狭い画面でも確認すれば、「画像は直ったのに別の場所がはみ出す」という失敗を防ぎやすくなります。

目的別に次の記事を選ぶ

次に整理したい内容に合わせて、関連記事を選んでください。

親と子の役割や、横並び・中央寄せの基本を学び直したい方はこちらの記事へ。

画面幅による切り替えや、max-width・min-widthのメディアクエリを整理したい方はこちらの記事へ。

この記事を書いた人

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

目次