CSSでflexを折り返し表示する方法|flex-wrapできれいに並べるコツ

CSS

CSSのflex(フレックスボックス)は、要素を横や縦に並べるとても便利な仕組みです。

でも「横並びにしたら画面からはみ出してしまった」「小さい画面で崩れてしまった」なんて経験はありませんか?

そんなときに活躍するのが flex-wrap です。

これを使うと、flexアイテムが自動で折り返し、見た目がきれいに整います。

この記事では、CSSでflexを折り返し表示する基本から、間隔を調整するコツまでわかりやすく解説します。

スポンサーリンク

Flexboxの基本概念と折り返しの必要性

Flexboxとは?

Flexboxの基本的な仕組み

Flexbox(Flexible Box Layout) 要素を1次元(横または縦)に配置するためのCSS機能です。従来のfloatやpositionよりもはるかに直感的で強力なレイアウト手法です。

身近な例で理解する

本棚の整理に例えると

  • 普通の本棚:本のサイズはバラバラ、隙間も不揃い
  • Flexbox:本が自動的に整列、スペースを効率的に活用
  • flex-wrap:棚が一杯になったら次の段に自動移動

電車の座席に例えると

  • 通常:決まった席に座る(固定レイアウト)
  • Flexbox:空いてる席に自動で詰めて座る
  • flex-wrap:座席が一杯になったら次の車両へ

なぜ折り返しが必要なの?

レスポンシブデザインの重要性

  • デスクトップ:横幅1200px
  • タブレット:横幅768px
  • スマートフォン:横幅375px

固定レイアウトの問題

/* 問題のあるコード例 */
.container {
  display: flex;
}

.item {
  width: 300px;  /* 固定幅 */
}

スマートフォンでは300px × 4個 = 1200pxとなり、画面からはみ出してしまいます。

Flexboxの主要プロパティ

コンテナ(親要素)のプロパティ

基本設定

.flex-container {
  display: flex;                /* Flexboxを有効化 */
  flex-direction: row;          /* 配置方向(横並び) */
  flex-wrap: nowrap;           /* 折り返し設定 */
  justify-content: flex-start; /* 主軸方向の配置 */
  align-items: stretch;        /* 交差軸方向の配置 */
}

アイテム(子要素)のプロパティ

柔軟性の制御

.flex-item {
  flex-grow: 0;    /* 伸びる比率 */
  flex-shrink: 1;  /* 縮む比率 */
  flex-basis: auto; /* 基準サイズ */
}

デフォルトの動作:folding(折り返しなし)

flex-wrap: nowrapの動作

デフォルトの状態

標準的なFlexbox

.container {
  display: flex;
  /* flex-wrap: nowrap; ← これがデフォルト */
}

.item {
  background: #007bff;
  color: white;
  padding: 20px;
  margin: 5px;
  min-width: 200px;
}

何が起こるの?

アイテムの縮小

  • コンテナの幅が不足すると、アイテムが自動的に縮小
  • min-widthが設定されていても、さらに縮むことがある
  • 最悪の場合、内容が読めなくなる

はみ出しの発生

.item {
  flex-shrink: 0;  /* 縮小を禁止 */
  width: 300px;    /* 固定幅 */
}
/* → コンテナからはみ出す */

よくある問題と症状

画面からのはみ出し

症状

  • 横スクロールバーが出現
  • 右側のアイテムが見えなくなる
  • モバイルで操作しにくい

具体例

<div class="container">
  <div class="card">カード1</div>
  <div class="card">カード2</div>
  <div class="card">カード3</div>
  <div class="card">カード4</div>
</div>
.container {
  display: flex;
  width: 800px;
}

.card {
  width: 250px;  /* 250px × 4 = 1000px > 800px */
  /* はみ出してしまう */
}

不自然な縮小

症状

  • テキストが読めないほど小さくなる
  • 画像のアスペクト比が崩れる
  • レイアウトが意図と異なる

flex-wrapプロパティの詳細

flex-wrapの3つの値

nowrap(デフォルト)

動作

.container {
  display: flex;
  flex-wrap: nowrap;
}

特徴

  • アイテムを1行に強制配置
  • 必要に応じてアイテムが縮小
  • はみ出すリスクあり

wrap(折り返しあり)

動作

.container {
  display: flex;
  flex-wrap: wrap;
}

特徴

  • コンテナ幅を超えたら次の行へ
  • アイテムの元サイズを保持
  • レスポンシブレイアウトに最適

wrap-reverse(逆方向折り返し)

動作

.container {
  display: flex;
  flex-wrap: wrap-reverse;
}

特徴

  • 折り返し方向が逆(上向き)
  • 特殊なデザインで使用
  • 通常はwrapを使用

実践的なwrapの活用

基本的な折り返しレイアウト

HTMLの構造

<div class="gallery">
  <div class="photo">写真1</div>
  <div class="photo">写真2</div>
  <div class="photo">写真3</div>
  <div class="photo">写真4</div>
  <div class="photo">写真5</div>
  <div class="photo">写真6</div>
</div>

CSSの設定

.gallery {
  display: flex;
  flex-wrap: wrap;
}

.photo {
  width: 300px;
  height: 200px;
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  margin: 10px;
}

カードレイアウトの実装

レスポンシブカード

.card-container {
  display: flex;
  flex-wrap: wrap;
  padding: 20px;
}

.card {
  flex: 1 1 300px;  /* grow shrink basis */
  max-width: 400px;
  min-width: 250px;
  margin: 10px;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

どう動作する?

  • デスクトップ:3〜4列で表示
  • タブレット:2〜3列で表示
  • スマートフォン:1〜2列で表示

gapプロパティで間隔を美しく調整

gapプロパティの基本

従来の間隔調整の問題

marginを使った古い方法

.item {
  margin: 10px;
}

/* 問題点 */
/* - 最初と最後にも余白がつく */
/* - 計算が複雑 */
/* - レスポンシブ対応が困難 */

gapプロパティの利点

シンプルで直感的

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

/* メリット */
/* - アイテム間のみに間隔 */
/* - 縦横の間隔を別々に設定可能 */
/* - 計算不要 */

gapの詳細な使い方

統一間隔

同じ間隔

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;  /* 横と縦の間隔が同じ */
}

個別間隔設定

行と列で異なる間隔

.container {
  display: flex;
  flex-wrap: wrap;
  row-gap: 2rem;     /* 行間隔 */
  column-gap: 1rem;  /* 列間隔 */
}

/* または短縮記法 */
.container {
  gap: 2rem 1rem;  /* 行間隔 列間隔 */
}

レスポンシブな間隔調整

画面サイズに応じた間隔

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

@media (min-width: 768px) {
  .container {
    gap: 1.5rem;
  }
}

@media (min-width: 1024px) {
  .container {
    gap: 2rem;
  }
}

実用的なgap活用例

ギャラリーレイアウト

写真ギャラリー

.photo-gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1rem;
}

.photo {
  flex: 1 1 250px;
  max-width: 350px;
  height: 200px;
  object-fit: cover;
  border-radius: 8px;
}

ボタングループ

アクションボタンの配置

.button-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}

.btn {
  padding: 0.5rem 1rem;
  border: 1px solid #007bff;
  background: white;
  color: #007bff;
  text-decoration: none;
  border-radius: 4px;
  transition: all 0.2s;
}

.btn:hover {
  background: #007bff;
  color: white;
}

高度な折り返しテクニック

flex-basisとの組み合わせ

柔軟なアイテムサイズ

理想的な幅の指定

.flexible-item {
  flex: 1 1 300px;
  /* 
  flex-grow: 1    - 余ったスペースを伸びて埋める
  flex-shrink: 1  - 必要に応じて縮む
  flex-basis: 300px - 基準となる幅
  */
}

最小・最大幅の制御

範囲指定による制御

.controlled-item {
  flex: 1 1 250px;
  min-width: 200px;  /* これより小さくならない */
  max-width: 400px;  /* これより大きくならない */
}

align-contentで行の配置制御

複数行の配置

行全体の配置

.multi-line-container {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;
  height: 400px;  /* 高さを指定 */
}

/* align-contentの値 */
/* stretch (デフォルト) - 行を引き延ばす */
/* flex-start - 上詰め */
/* flex-end - 下詰め */
/* center - 中央揃え */
/* space-between - 行間を均等配置 */
/* space-around - 行の周りに余白 */
/* space-evenly - 完全に均等配置 */

実用例:カードレイアウトでの活用

均等配置のカード

.card-deck {
  display: flex;
  flex-wrap: wrap;
  align-content: space-evenly;
  min-height: 500px;
  gap: 1rem;
  padding: 1rem;
}

.card {
  flex: 1 1 calc(33.333% - 1rem);
  max-width: 300px;
  min-height: 200px;
}

条件付き折り返し

メディアクエリとの組み合わせ

画面サイズに応じた折り返し制御

.responsive-container {
  display: flex;
}

/* モバイル:必ず折り返し */
@media (max-width: 767px) {
  .responsive-container {
    flex-wrap: wrap;
  }
  
  .responsive-item {
    flex: 1 1 100%;  /* 1列表示 */
  }
}

/* タブレット:2列まで */
@media (min-width: 768px) and (max-width: 1023px) {
  .responsive-container {
    flex-wrap: wrap;
  }
  
  .responsive-item {
    flex: 1 1 calc(50% - 1rem);
  }
}

/* デスクトップ:折り返しなし */
@media (min-width: 1024px) {
  .responsive-container {
    flex-wrap: nowrap;
  }
  
  .responsive-item {
    flex: 1;
  }
}

実践的なレイアウト例

ブログカードレイアウト

HTML構造

<section class="blog-posts">
  <article class="post-card">
    <img src="post1.jpg" alt="記事1" class="post-image">
    <div class="post-content">
      <h3 class="post-title">記事タイトル1</h3>
      <p class="post-excerpt">記事の概要が入ります...</p>
      <time class="post-date">2024年1月15日</time>
    </div>
  </article>
  
  <article class="post-card">
    <img src="post2.jpg" alt="記事2" class="post-image">
    <div class="post-content">
      <h3 class="post-title">記事タイトル2</h3>
      <p class="post-excerpt">記事の概要が入ります...</p>
      <time class="post-date">2024年1月10日</time>
    </div>
  </article>
  
  <!-- 他の記事カード -->
</section>

CSS実装

.blog-posts {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  padding: 2rem;
  max-width: 1200px;
  margin: 0 auto;
}

.post-card {
  flex: 1 1 300px;
  max-width: 400px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: transform 0.2s, box-shadow 0.2s;
}

.post-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
}

.post-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.post-content {
  padding: 1.5rem;
}

.post-title {
  margin: 0 0 1rem 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: #333;
}

.post-excerpt {
  margin: 0 0 1rem 0;
  color: #666;
  line-height: 1.6;
}

.post-date {
  font-size: 0.875rem;
  color: #999;
}

ECサイトの商品一覧

商品グリッドレイアウト

.product-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  padding: 1rem;
}

.product-item {
  flex: 1 1 250px;
  max-width: 320px;
  background: white;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

.product-image {
  width: 100%;
  height: 250px;
  object-fit: cover;
}

.product-info {
  padding: 1rem;
}

.product-name {
  font-weight: 600;
  margin-bottom: 0.5rem;
  color: #333;
}

.product-price {
  font-size: 1.25rem;
  font-weight: 700;
  color: #e74c3c;
  margin-bottom: 1rem;
}

.product-button {
  width: 100%;
  padding: 0.75rem;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.2s;
}

.product-button:hover {
  background: #0056b3;
}

/* レスポンシブ調整 */
@media (max-width: 480px) {
  .product-grid {
    gap: 1rem;
  }
  
  .product-item {
    flex: 1 1 calc(50% - 0.5rem);
  }
}

ナビゲーションメニュー

レスポンシブナビゲーション

.main-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 2rem;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.nav-brand {
  font-size: 1.5rem;
  font-weight: 700;
  color: #333;
  text-decoration: none;
}

.nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-link {
  color: #666;
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s;
}

.nav-link:hover {
  color: #007bff;
}

/* モバイル対応 */
@media (max-width: 768px) {
  .main-nav {
    flex-direction: column;
    align-items: stretch;
    gap: 1rem;
  }
  
  .nav-links {
    justify-content: center;
    gap: 1rem;
  }
}

トラブルシューティング

よくある問題と解決法

問題1:折り返しが効かない

症状 flex-wrapを設定したのに折り返されない

原因と解決法

/* 問題のあるコード */
.container {
  display: flex;
  flex-wrap: wrap;
}

.item {
  flex-shrink: 0;
  width: 300px;
  min-width: 300px;  /* 問題:最小幅が大きすぎる */
}

/* 解決法 */
.item {
  flex: 1 1 250px;   /* basisを適切なサイズに */
  max-width: 350px;  /* 最大幅で制限 */
}

問題2:アイテムの高さが揃わない

症状 カードの高さがバラバラになる

解決法

.container {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;  /* デフォルトで高さを揃える */
}

.item {
  display: flex;
  flex-direction: column;  /* 内部も縦並び */
}

.item-content {
  flex: 1;  /* 可変部分 */
}

.item-footer {
  /* 固定部分:下に配置 */
  margin-top: auto;
}

問題3:gapが効かない

症状 gapプロパティが無視される

原因と解決法

/* 原因:古いブラウザサポート */
/* Safari 14.1未満、IE11では未対応 */

/* 解決法:フォールバック用のmargin */
.container {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin: -0.5rem;  /* フォールバック */
}

.item {
  margin: 0.5rem;  /* フォールバック */
}

/* モダンブラウザ用の調整 */
@supports (gap: 1rem) {
  .container {
    margin: 0;
  }
  
  .item {
    margin: 0;
  }
}

パフォーマンスの考慮

大量アイテムでの最適化

仮想化の検討

/* 大量のアイテムがある場合 */
.large-grid {
  display: flex;
  flex-wrap: wrap;
  /* contain: layout style; CSS Containment */
}

/* JavaScriptでの仮想スクロール実装を推奨 */

アニメーション時の注意

スムーズなトランジション

.animated-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.grid-item {
  transition: transform 0.2s ease;
  /* transform のみをアニメーション */
  /* width, height の変更は避ける */
}

.grid-item:hover {
  transform: scale(1.05);
}

まとめ

CSSのFlexboxで折り返しレイアウトを作成する方法について詳しく解説しました。

基本的な折り返し設定

  • **flex-wrap: wrap**で自動折り返し
  • gapプロパティで美しい間隔調整
  • レスポンシブ対応で全デバイス対応

重要なポイント

  • デフォルトは折り返しなし(nowrap)
  • 適切なflex-basisでアイテムサイズを制御
  • min-width、max-widthで範囲制限

実用的なテクニック

  • カードレイアウトでの活用
  • ギャラリー表示の実装
  • レスポンシブナビゲーション
  • ECサイトの商品一覧

トラブル対応

  • 折り返しが効かない場合の対処
  • 高さ揃えの方法
  • 古いブラウザでのフォールバック

ベストプラクティス

  • モバイルファーストでの設計
  • パフォーマンスを考慮した実装
  • アクセシビリティへの配慮

コメント

タイトルとURLをコピーしました