gap と margin の使い分け
問題
要素間のスペーシングは最もよくあるCSSタスクの1つですが、AIエージェントは flex や grid コンテナ内でも gap が正しいツールであるにもかかわらず、あらゆる状況で margin を使いがちです。margin ベースのスペーシングにはいくつかの問題があります:アイテムが隣接する場所でマージンが二重になる、first/last child のワークアラウンドが必要、ブロックフローでのマージンの相殺、アイテムが折り返す際の不均一なスペーシングなどです。gap プロパティは flexbox、grid、マルチカラムレイアウトで利用可能で、これらの問題をすべて解決します。
解決方法
flex、grid、またはマルチカラムコンテナ内の兄弟アイテム間のスペーシングには gap を使いましょう。要素の周囲のスペーシングや、同じレイアウトコンテナ内の兄弟ではない要素間のスペーシングには margin を使いましょう。
重要な違い:gap はアイテム間にのみスペースを作り、最初のアイテムの前や最後のアイテムの後にはスペースを作りません。margin はすべての要素の周囲にスペースを作るため、二重スペーシングや端のスペーシングを避けるためのワークアラウンドが必要です。
コード例
margin の問題
/* Margin creates spacing issues */
.list-item {
margin-bottom: 1rem;
}
/* Problem 1: Last item has unwanted bottom margin */
/* Fix attempt: */
.list-item:last-child {
margin-bottom: 0;
}
/* Horizontal layout with margin */
.tag {
margin-right: 0.5rem;
}
/* Problem 2: Last item has unwanted right margin */
.tag:last-child {
margin-right: 0;
}
gap による解決
/* Gap only creates space BETWEEN items */
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
/* No :last-child workaround needed. No double spacing. */
<div class="tag-list">
<span class="tag">CSS</span>
<span class="tag">Grid</span>
<span class="tag">Flexbox</span>
</div>
ブロックフローでのマージンの相殺
ブロック要素間の垂直マージンは相殺されます。ブラウザは合計ではなく、大きい方のマージンを使用します。
.heading {
margin-bottom: 1rem;
}
.paragraph {
margin-top: 1.5rem;
}
/* The space between heading and paragraph is 1.5rem, not 2.5rem */
これは仕様通りの動作ですが、AIエージェントを混乱させることが多く、「足りない」と感じたスペースを補うために任意のマージン増加を行うことがあります。
マージンの相殺が起こらない場合
マージンの相殺は通常のブロックフローでのみ発生します。以下の場合には発生しません:
- flex コンテナ内
- grid コンテナ内
- フロートされた要素
- absolute positioned の要素
- 親が
visible以外のoverflowを持つ場合 - 親が相殺される辺に padding または border を持つ場合
/* No margin collapse: items are flex children */
.flex-container {
display: flex;
flex-direction: column;
}
.flex-container > .item {
margin-block: 1rem;
/* Adjacent margins DO NOT collapse. Total space = 2rem between items. */
}
グリッドレイアウトでの gap
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
gap: 1.5rem;
}
すべてのカードは水平・垂直方向にぴったり 1.5rem のスペースを持ちます。margin のワークアラウンドは不要です。
行と列で異なる gap
.layout {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
row-gap: 2rem;
column-gap: 1rem;
/* Or shorthand: gap: 2rem 1rem; */
}
flex レイアウトでの gap
.toolbar {
display: flex;
align-items: center;
gap: 0.75rem;
}
<div class="toolbar">
<button>Save</button>
<button>Cancel</button>
<span class="separator"></span>
<button>Delete</button>
</div>
すべてのアイテムは隣のアイテムとの間にぴったり 0.75rem のスペースを持ちます。margin ルールも :first-child や :last-child のオーバーライドも不要です。
gap と margin の組み合わせ
gap と margin は異なる目的を持ち、一緒に使えます:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
gap: 1.5rem; /* Space between cards */
margin-block-end: 3rem; /* Space after the entire grid */
}
.card {
padding: 1.5rem; /* Space inside each card */
/* No margin needed — gap handles inter-card spacing */
}
margin が正しい選択である場合
/* Centering a block element */
.container {
max-inline-size: 1200px;
margin-inline: auto;
}
/* Space between unrelated sections */
.section + .section {
margin-block-start: 4rem;
}
/* Space between elements that are NOT siblings in a flex/grid container */
.page-title {
margin-block-end: 2rem;
}
AIがよくやるミス
- コンテナに
gapを使う代わりに、flex/grid の子要素にmarginを使っている。 これが最もよくあるミスです。flex や grid コンテナ内のアイテムには、gapの方がシンプルで予測可能であり、二重スペーシングの問題を避けられます。 - マージンの相殺を理解していない。 AIエージェントは隣接する要素に
margin-top: 1remとmargin-bottom: 1remを追加し、2rem のスペースを期待します。ブロックフローでは 1rem に相殺されます。これは混乱したデバッグや任意のマージン増加につながります。 - gap の問題を「修正」するためにネガティブマージンを使っている。 よくあるアンチパターン:アイテムの
margin: 0.5remを打ち消すためにコンテナにmargin: -0.5remを適用する方法です。gapはこれを完全に不要にします。 :last-child { margin: 0 }のワークアラウンドを追加している。 first child や last child のマージンを削除している場合、代わりにgapを使うべきです。- flex/grid 以外のコンテナで
gapを使っている。gapはdisplay: flex、display: grid、display: multi-columnのコンテナでのみ機能します。通常のブロック要素では効果がありません。 - flex/grid コンテナではマージンの相殺が無効になることを忘れている。 要素をブロックから flex/grid に切り替えると、相殺が起こらなくなるため、既存のマージンベースのスペーシングが二倍になる可能性があります。
- コンポーネント内のスペーシングに
marginを使い、コンポーネント間にはgapを使う(またはその逆)。 一貫性を保ちましょう:レイアウトコンテナ(flex/grid)内ではgapを、セクション間や無関係な要素間の外部スペーシングにはmarginを使いましょう。
使い分け
gap を使う場面
- flex コンテナの子要素間のスペーシング(ナビゲーションアイテム、ボタン、タグ)
- grid コンテナの子要素間のスペーシング(カードグリッド、フォームレイアウト)
- first/last child のワークアラウンドなしで均一なスペーシングが必要な場合
- アイテムが折り返す可能性があり、すべての行で均一な gap が必要な場合
margin を使う場面
- ブロック要素のセンタリング(
margin-inline: auto) - flex/grid の兄弟ではないセクション間や無関係な要素間のスペーシング
- コンポーネントの周囲のコンテンツとのスペーシング
- マージンの相殺動作を理解し意図的に使いたい通常のブロックフローでの作業
padding を使う場面
- 要素内部のスペース(コンテンツとボーダーの間)の作成
- スペースを要素の背景やクリック可能なエリアの一部にする必要がある場合
Tailwind CSS
Tailwind は flex や grid コンテナの gap-* ユーティリティで、gap を自然な選択にしています。