CSS中央寄せのやり方|手法の選び分けと効かない原因の数値診断


CSSの中央寄せで手が止まるのは、手法を知らないからではなく、手法が多すぎてどれを選べばよいか決まらないからです。そして選んだあとにもう一度止まります。指定したのに中央に来ない、という状態です。

CSS中央寄せとは、要素を親要素または画面の水平・垂直方向の中心に配置する指定の総称です。使うプロパティは「何を・どの軸で中央にしたいか」で一意に決まります。水平だけなら margin-inline: autotext-align: center、垂直だけなら align-content: center、上下左右まとめてなら Flexbox か Grid です。

本記事は、その選び分けの表を先頭に置き、各手法が実際にどう効くのかを数値で示し、最後に「効いているつもりで効いていない」ときにブラウザのコンソールで原因を数値として切り出す手順までをまとめた実務リファレンスです。掲載した数値はすべて Chrome 150(macOS)で実際にレンダリングし、getBoundingClientRect() で計測した実測値です(計測日 2026年8月2日)。


CSS中央寄せは「何を・どの軸で」中央にするかで決まる

中央寄せの手法は10個近くありますが、実務で迷う場面は「対象がテキストか要素か」「軸が横か縦か両方か」「子が1つか複数か」の3点でほぼ確定します。先に判断軸を決めてから表を引くと、選択肢は1つに絞れます。

まず結論:迷ったらこの3つで足りる

  1. 親の display を変えたくないとき — 親に heightalign-content: center、子に margin-inline: auto。Flexbox も Grid も使わずに上下左右中央になります
  2. 子が1つで上下左右中央にしたいとき — 親に display: grid; place-items: center;
  3. 子が複数あって、まとめて中央に置きたいとき — 親に display: grid; place-content: center;

1番目は2024年から全ブラウザで使えるようになった書き方で、既存のレイアウトに手を入れずに済むため副作用が最も小さい選択肢です。実測では、親400×300pxのブロック要素の中に幅120pxの子を置いたところ、左140px/右140px、上138px/下138pxで両軸中央になりました。

中央寄せ手法の早見表

左端の「やりたいこと」から引いてください。同じ「上下左右中央」でも、子の数と幅を決めるかどうかで書き方が変わります。

やりたいこと使うもの書き方
テキスト・インライン要素を水平中央text-align親に text-align: center
ブロック要素を水平中央margin子に margin-inline: auto(幅の指定が必要)
画像を水平中央display + margin子に display: block; margin-inline: auto
display を変えずに垂直中央align-content親に heightalign-content: center(2024年〜)
子1つを上下左右中央(Flexbox)Flexbox親に justify-content: center; align-items: center
子1つを上下左右中央(Grid)Grid親に place-items: center
幅を決めずに上下左右中央flex / grid の子の margin親を flex か grid にして、子に margin: auto
絶対配置の要素を中央inset + margin子に position: absolute; inset: 0; margin: auto とサイズ指定
複数の子をひとかたまりで中央Grid親に place-content: center
モーダルを画面中央dialog 要素<dialog>showModal()(ブラウザ標準で中央)

表に出てくる place-itemsalign-contentmargin-inline のように名前が似たプロパティは、後から索引で引き直せるようにしておくと迷いが減ります。CSSプロパティ一覧(カテゴリ別リファレンス)に一通りまとめてあります。


水平方向の中央寄せ

横方向だけを中央にしたい場合、対象が「文字の並び」なのか「箱そのもの」なのかで使うプロパティが変わります。ここを取り違えると、指定は書けているのに何も動かない状態になります。

テキストとインライン要素は text-align: center

.container {
  text-align: center;
}

幅500pxの親でこれを実測すると、中のインライン要素(span)は左229.74px/右229.74pxで中央に来ました。ところが同じ親の中に置いたブロック要素の子は、左0px/右400pxのまま動きません。text-align が動かすのは行の中身であって、箱そのものではないためです。

落とし穴が2つあります。1つ目は継承です。text-align は継承するプロパティなので、親に一度書くと孫要素のテキストまで中央になります(実測でも、入れ子にした段落の算出値が center になりました)。範囲を限定したい場合は、対象の要素に直接書くか、子側で text-align: left に戻す必要があります。

2つ目は、Flexboxのアイテムには効かないことです。親を display: flex にしたうえで text-align: center を足しても、実測でアイテムは左0px/右280pxのまま中央になりませんでした。Flexアイテムの位置を動かすのは justify-content であり、text-align はアイテムの内側の文字にしか届きません。

ブロック要素は margin-inline: auto(margin: 0 auto の現行版)

.box {
  width: 50%;
  margin-inline: auto;
}

親400pxに対して実測で左100px/右100px。従来の margin: 0 auto と横書きでは結果が完全に一致します(同条件で左100px/右100px)。違いが出るのは書字方向を変えたときです。

親に writing-mode: vertical-rl を指定した200×400pxの領域で、高さ50%の子を中央に寄せる実測結果です。margin-inline: auto は上100px/下100pxで中央になりましたが、margin: 0 auto は上0px/下200pxで中央になりませんでした。margin-inline は「文字が流れる方向」を基準に解決されるため、縦書きでは自動的に上下方向へ切り替わります。横書き固定のサイトなら結果は同じですが、書字方向を切り替える可能性があるなら margin-inline を選んでおくと安全です。

対応状況は margin-inline が Baseline widely available(Chrome 87・Firefox 66・Safari 14.1 以降)で、実務で対応を気にする段階は過ぎています。

「width の指定が必要」の正確な条件。通常フローのブロック要素は幅が親いっぱいに広がるため、widthmax-width を指定しないと左右に余白が生まれず、auto が配れるものがなくなります。ただし、よく見かける「指定しないとデフォルトで幅100%になるから」という説明は正確ではありません。初期値の width: auto は「利用できる幅を埋める」であって width: 100% とは別物です。実測でも、親400pxの中で width: 100%; padding: 0 24px; を指定した要素は448pxになって48pxはみ出しましたが、width を書かずに同じ padding を付けた要素は400pxに収まりました。

そして width が要るのは通常フローのブロック要素に限った話です。Flexboxやgridの子要素、あるいは inset: 0 を付けた絶対配置の要素では、width を書かなくても margin: auto だけで中央になります(後述)。

画像に display: block を足す理由

img {
  display: block;
  margin-inline: auto;
}

img は初期状態がインラインレベルの要素なので、そのままでは左右の margin: auto が余白を配る対象になりません。display: block を足すことでブロックとして扱われ、実測で親400px・画像100pxに対し左150px/右150pxの中央に来ました。親側に text-align: center を書く方法でも同じ結果になりますが、その場合は親の中のテキストもすべて中央寄せになる点に注意してください。


垂直方向の中央寄せ

縦方向の中央寄せは、横方向と違ってまず親に高さがあることが前提になります。高さのない親の中で「上下中央」を指定しても、寄せる余白そのものが存在しないため何も起きません。

Flexbox の align-items: center(親の高さが要る)

.container {
  display: flex;
  align-items: center;
  min-height: 320px;
}

この min-height を外すと何が起きるかを実測しました。親の高さを指定せずに display: flex; align-items: center; だけを書いた場合、親の高さは子と同じ40pxに縮み、子の上余白0px/下余白0pxになります。指定自体は効いているのに、寄せる先の余白がゼロなので見た目が変わらない、という状態です。垂直中央が効かないときは、まず親の高さを疑ってください。

display を変えずに縦中央にする align-content: center(2024年〜)

.container {
  height: 300px;
  align-content: center;
}

align-content はもともとFlexboxとGridのためのプロパティでしたが、通常のブロックレイアウトにも適用されるようになりました。実測で、親400×300pxの中に高さ24pxの子を置くと上138px/下138pxの縦中央になります。displayflexgrid に変えないので、子要素の回り込みやマージン相殺といった既存の挙動を壊さずに縦中央だけを足せるのが利点です。

対応状況は Baseline newly available(2024年4月16日)、Chrome 123・Firefox 125・Safari 17.4 以降です。比較的新しい書き方なので、これより古いブラウザを対象に含む場合はFlexboxを併用してください。

横方向の margin-inline: auto と組み合わせると、Flexbox も Grid も使わずに上下左右中央が完成します。実測では左140px/右140px、上138px/下138pxでした。

.container {
  height: 300px;
  align-content: center;
}

.box {
  width: 120px;
  margin-inline: auto;
}

line-height が使えるのは1行のときだけ

親の高さと同じ line-height を指定して縦中央にする書き方は、いまでも1行のボタンやバッジでは有効です。ただし折り返しが起きた瞬間に破綻します。

実測です。高さ200pxの親に line-height: 200px の子を置くと、1行のときは中央に収まりますが、テキストが2行に折り返した瞬間に子の高さが400pxになり、親から200pxはみ出しました。行数が可変になりうる箇所では使わず、Flexbox か align-content を使ってください。


上下左右まとめて中央にする4つの書き方

両軸をいっぺんに中央へ寄せる方法は4つあり、実測ではどれも同じ位置に着地します。違いは「子の幅を自分で決めるかどうか」と「既存のレイアウトをどれだけ壊すか」です。

Flexbox:justify-content と align-items

.container {
  display: flex;
  justify-content: center; /* 水平方向 */
  align-items: center;     /* 垂直方向 */
  min-height: 100dvh;
}

最も使用頻度が高い書き方です。実測で幅400pxの親に120×40pxの子を置くと左140px/右140px、上下も中央に来ました。Flexboxは Baseline widely available(2018年3月時点で主要ブラウザが出揃っています)なので、対応状況を気にする段階はとうに過ぎています。justify-contentalign-items の値を変えたときに何がどう動くのかは、Flexboxの各プロパティの効き方をジェネレーターで確認すると手を動かしながら把握できます。

ここで 100vh ではなく 100dvh を使っている点だけ補足します。スマートフォンではアドレスバーの表示・非表示で表示領域が変わるため、100vh のままだと画面下が隠れることがあります。単位の使い分けはモバイルの100vh問題と dvh / svh / lvh の使い分けで扱っているので、そちらを参照してください。

Grid:place-items: center

.container {
  display: grid;
  place-items: center;
  min-height: 100dvh;
}

1行で済むのが利点で、実測結果もFlexbox版と完全に一致しました(左140px/右140px)。

ただし副作用が1つあります。gridの子要素は既定で親の幅いっぱいに引き伸ばされますが、place-items: center を付けるとこの引き伸ばしが止まり、内容の幅まで縮みます。実測では、親400pxのgridで子は既定なら400pxだったものが、place-items: center を付けると127.23pxに縮んで左右136.38pxずつになりました。背景色を敷いていた要素が突然細くなった場合は、これが原因です。幅を保ちたいなら子側で width を指定するか、align-items: center だけを使ってください。

flex / grid の子に margin: auto(width を書かなくてよい)

.container {
  display: flex;
  height: 200px;
}

.box {
  margin: auto;
}

親に justify-contentalign-items も書かず、子に margin: auto を1行書くだけの方法です。実測では、子は内容幅の94.13pxに縮み、左152.94px/右152.93px、上88px/下88pxで両軸中央になりました。display: grid の子でも同じ結果です(左152.93px/右152.94px)。

ここが「margin: auto には width が必要」という通説の例外です。flex や grid の子は幅が自動的に内容サイズへ縮むため、余白が生まれ、auto がそれを左右へ等分できます。子の1つだけを中央に置きたくて、他の子は元の配置のままにしたい、という場面で使えます。

絶対配置:inset: 0 と margin: auto(transform を使わない版)

.container {
  position: relative;
  height: 200px;
}

.box {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 120px;
  height: 60px;
}

実測で左140px/右140px、上70px/下70px。おなじみの top: 50%; left: 50%; transform: translate(-50%, -50%); と同じ条件で比べたところ、結果は1pxの違いもなく一致しました(どちらも左140px/右140px、上70px/下70px)。

この書き方には必ずサイズ指定を添えてください。widthheight を省くと、inset: 0 によって要素が親いっぱいに広がります(実測で400×200pxの親に対し子も400×200pxになりました)。transform 版と違い、サイズを書き忘れると中央寄せどころか要素が全面を覆ってしまう点が唯一の注意点です。

なお「transform による中央寄せは0.5px単位でずれて文字がにじむ」という説明を見かけることがありますが、今回の計測では裏づけられませんでした。親を401×201pxという割り切れないサイズにして両方を比較しても、Flexbox版・transform版ともに左140.5px/右140.5px、上80.5px/下80.5pxで同じ値でした。0.5px単位の値が出るのは奇数pxを2で割った正常な結果であり、手法による差ではありません。


place-items と place-content を取り違えない

名前が似ている2つですが、役割は明確に違います。place-itemsalign-itemsjustify-items の一括指定で、各アイテムを自分のトラックの中で寄せますplace-contentalign-contentjustify-content の一括指定で、トラックの集まりそのものをコンテナの中で寄せます

子が1つのときは結果がほぼ同じなので違いに気づきません。子を2つにすると決定的に変わります。以下は親400×200px、gap: 8px、子2つで計測した結果です。

指定1つ目の子(上余白/下余白)2つ目の子(上余白/下余白)見た目
place-content: center72px / 104px104px / 72px2つがくっついたまま、かたまりで中央
place-items: center36px / 140px140px / 36px上下2段に分かれ、それぞれの段の中で中央

判断はこうなります。カードやボタンを並べて「ひとかたまりとして」画面中央に置きたいなら place-contentグリッドのセルを固定したうえで各セルの中身を中央揃えにしたいなら place-items です。Gridのトラック定義そのものを組み立てる段階から確認したい場合は、CSS Grid のトラック定義を視覚的に作ると挙動を見ながら決められます。

そして、早見表の類でよく見かける誤りをここで潰しておきます。「上下左右中央にするなら Flexbox か Grid で place-items: center」という説明は、Flexboxについては成り立ちません。実測で display: flex; place-items: center; を指定すると、縦方向は上80px/下80pxで中央になるのに、横方向は左0px/右280pxのまま動きません

理由は仕様に書かれています。place-items の横方向側にあたる justify-items は、それ自体が要素を動かすプロパティではなく、子要素の justify-self: auto をどう解釈するかを決めるだけのプロパティです。そしてその justify-self について、CSS Box Alignment Module Level 3 は「このプロパティはflexアイテムには適用されない。主軸には複数のアイテムがあるためである」と明記しています。動かす相手が存在しないので、Flexコンテナでは横方向が沈黙する、というのが実測結果の中身です。

Flexboxでは justify-content: center; align-items: center; と2行で書いてください。1行で済ませたいなら display: grid に変えたうえで place-items: center を使います。


モーダルの中央寄せと、リセットCSSが壊す落とし穴

モーダルの中央寄せは、いまは自分でCSSを書く必要がほとんどありません。そして「自分で書いていない中央寄せ」だからこそ、壊れたときに原因を探しにくい領域でもあります。

dialog 要素は showModal() だけで中央に来る

<dialog>showModal() で開くと、位置に関するCSSを一切書かなくても画面中央に表示されます。これはブラウザ標準のスタイルシートが中央寄せを担当しているためで、HTML仕様には次のように定義されています。

/* HTML Standard が定めるブラウザ標準スタイル(抜粋) */
dialog {
  position: absolute;
  inset-inline-start: 0;
  inset-inline-end: 0;
  width: fit-content;
  height: fit-content;
  margin: auto;
}

dialog:modal {
  position: fixed;
  overflow: auto;
  inset-block: 0;
  max-width: calc(100% - 6px - 2em);
  max-height: calc(100% - 6px - 2em);
}

横方向は inset-inline-start / end: 0margin: auto、縦方向は :modal のときに加わる inset-block: 0margin: auto。つまりこの記事で扱ってきた「inset: 0margin: auto による中央寄せ」そのものがブラウザ側で最初から書かれている、という構造です。実測でも、リセットCSSなしの状態で showModal() した <dialog> は算出値が margin-left: 216.5pxmargin-top: 94px となり、auto が余白として解決されていることを確認できました。

リセットCSSの全称セレクタが dialog の中央寄せを壊す

ここが本記事で最も再現しにくい不具合です。モーダルが画面の左上に張り付く原因は、自分が書いたモーダル用のCSSではなく、プロジェクトの先頭で読み込んでいるリセットCSSにあることがあります。

600×260pxのビューポートで、リセットCSSだけを差し替えて showModal() した実測結果です。ダイアログのサイズはいずれも120×40pxで固定しています。

リセットCSS左からの距離上からの距離算出 margin-left中央か
リセットなし216.5px94px216.5px中央(横のわずかなずれはスクロールバー分)
* { margin: 0; padding: 0; }0px0px0px壊れる(左上に張り付く)
*,*::before,*::after { box-sizing: border-box } body { margin: 0 }240px110px240px中央
* { margin: 0 }dialog { margin: auto }240px110px240px中央(復旧)

原因は単純です。ブラウザ標準スタイルの margin: auto を、全称セレクタの * { margin: 0 } が上書きして消してしまうためです。inset: 0 だけが残るので、要素は左上の基準点に吸い寄せられます。算出値の margin-left0px になっている点がそのまま証拠です。

直し方は1行です。リセットCSSより後ろで dialog { margin: auto; } を書き戻せば中央に戻ります(実測で240px/110pxの中央に復旧)。あるいは、そもそも全称セレクタで margin を潰さないリセットCSSを選ぶことです。上の表の3行目にある現代的なリセットは box-sizing だけを全称セレクタで扱い、margin は body に限定しているため、<dialog> を壊しません。どのリセットCSSを選ぶかで副作用が変わる話は、リセットCSSの選び方と box-sizing の入れ方にまとめてあります。


中央寄せが効かないときの数値診断

ここからが本記事の本題です。中央寄せが効かないとき、DevToolsのスタイルパネルを目で追っても「なんとなくズレている」以上のことは分かりません。左右の余白と上下の余白を数値として取り出せば、原因は数パターンに機械的に分類できます。

コンソールに貼るだけの診断スニペット

始める前に1つだけ確認してください。そもそもCSSファイルが読み込まれていない、セレクタが一致していない、といった「中央寄せ以前の問題」であることも珍しくありません。指定した値がDevToolsのStylesに一切現れない場合は、CSSが効かない原因のチェックリストを先に通してください。値は当たっているのに位置が動かない、という段階まで来ていれば以下が使えます。

対象ページを開き、DevToolsのConsoleタブに以下をそのまま貼り付けてEnterを押します。最終行のセレクタを、中央に寄せたい要素のものに書き換えてください。

(sel => {
  const el = document.querySelector(sel);
  if (!el) return console.warn('要素が見つかりません: ' + sel);
  const p  = el.parentElement;
  const r  = el.getBoundingClientRect(), pr = p.getBoundingClientRect();
  const cs = getComputedStyle(el), ps = getComputedStyle(p);
  const L = r.left - pr.left, R = pr.right - r.right;
  const T = r.top  - pr.top,  B = pr.bottom - r.bottom;
  const notes = [];
  if (r.width  >  pr.width  + 0.5) notes.push('はみ出し(box-sizing疑い)');
  else if (r.width  >= pr.width  - 0.5) notes.push('横:余白ゼロ(子が親と同じ幅)');
  else if (Math.abs(L - R) > 0.5)  notes.push('横:ズレ' + (L - R).toFixed(1) + 'px');
  if (r.height >= pr.height - 0.5) notes.push('縦:余白ゼロ(親に高さが無い)');
  else if (Math.abs(T - B) > 0.5)  notes.push('縦:ズレ' + (T - B).toFixed(1) + 'px');
  if (cs.display === 'inline') notes.push('自分がinline');
  if (ps.display === 'inline') notes.push('親がinline');
  console.table({
    '左右差': +(L - R).toFixed(2), '上下差': +(T - B).toFixed(2),
    '子W×H': r.width.toFixed(1) + '×' + r.height.toFixed(1),
    '親W×H': pr.width.toFixed(1) + '×' + pr.height.toFixed(1),
    '親display': ps.display, '子display': cs.display, 'box-sizing': cs.boxSizing,
    '判定': notes.length ? notes.join(' / ') : 'OK(両軸中央・誤差0.5px以内)'
  });
})('.box');   // ← 中央に寄せたい要素のセレクタに変える

やっていることは、要素と親の矩形を getBoundingClientRect() で取り、上下左右の余白の差を計算しているだけです。ポイントは差を見る前に「そもそも余白が存在するか」を先に判定している点です。親に高さがない場合も、子が親と同じ幅の場合も、余白は両側とも0になるので「差はゼロ=中央」と誤って判定されてしまいます。子と親のサイズを先に比較することで、この2つを別の原因として切り分けています。

出力の読み方と合否ライン

Consoleに表を1つ出力します。見るのは3行だけです。

見る値合格不合格
左右差絶対値 0.5px 以内0.5px を超える
上下差絶対値 0.5px 以内0.5px を超える
判定OK(両軸中央・誤差0.5px以内) と出るそれ以外の文字列が出る

0.5pxを境界にした理由も実測で決めています。親401×201pxのような割り切れないサイズでは、余白が140.5pxのように0.5px単位で出るのが正常です。さらに、幅を指定せず内容に合わせて縮む要素では、文字幅の端数がそのまま余白に乗ります。実測では margin-inline: auto でも margin: auto でも、左右差として0.008px程度の値が残りました。これを不合格にすると正常な中央寄せまで弾いてしまうため、0.5pxを許容幅としています。逆に言えば、0.5pxを超える差が出ているなら、それは端数ではなく設計上の原因があります。

判定別・原因と直し方

「判定」欄に出た文字列から、原因と次の1手が決まります。以下の表はすべて実際に不具合を再現したうえで、スニペットが正しく分類することを確認した内容です。1つ直したらもう一度スニペットを実行し、判定がOKに変わったところで終わりにしてください。複数を同時に直すと、どれが効いたのか分からなくなります。

判定欄の出力再現条件(実測)原因直し方(1手だけ)
OK(両軸中央・誤差0.5px以内)Flexbox / Grid / 絶対配置+transform / ブロック+align-content の4通りで確認完了。これ以上は調べない
縦:余白ゼロ(親に高さが無い)flexで中央寄せ指定済みだが親に height なし。親が子と同じ40pxに縮む寄せる先の余白が存在しない親に min-heightheight を入れる
横:余白ゼロ(子が親と同じ幅)margin: 0 auto だが子に width なし。子400px=親400px通常フローのブロックは幅いっぱいに広がる子に widthmax-width を入れる。または親を display: flex にする
はみ出し(box-sizing疑い)width: 100%padding: 0 24px で子448px > 親400px(左右差48px)padding / border が width に加算されている*,*::before,*::after { box-sizing: border-box } を入れる
自分がinlinedisplay: inline の要素に margin: 0 auto。左右差 −391.4pxインライン要素には width も左右の margin: auto も効かないdisplay: block(または inline-block)にする
親がinline親が display: inline のまま height: 200px を指定。高さが無視されるインライン要素に height は効かない親を display: block / flex / grid にする
横:ズレ○○px(上下差は0)display: flex; place-items: center; → 左右差 −280pxjustify-items がFlexアイテムに適用されないplace-items をやめて justify-content: center; align-items: center; にする

やってはいけない・まだ使えない中央寄せ

手元のChromeで動いたからといって本番に出せるとは限りません。中央寄せの文脈でよく名前が挙がるものの、2026年8月時点で採用を見送るべき3つを、実際に動かした結果とあわせて挙げます。

機能手元での実測対応状況結論
ブロックレイアウトの justify-self: centerChrome 150 では動く(幅を指定しなければ内容幅に縮んで左右131.83px/131.84px)Chrome / Edge 130 のみ。Firefox・Safari は未対応本番で使わない。横方向は margin-inline: auto で代替する
アンカーポジショニング(position-area: centerChrome 150 では動作するweb-features では Baseline 未達。一方 caniuse は Chrome 125以降・Firefox 147以降・Safari 26以降を対応として扱っており、2つの資料で評価が食い違っていますそもそも「アンカーとなる要素を基準に配置する」機能で、親の中央に置く用途の道具ではない。中央寄せの選択肢としては不要
text-box-trim / text-boxFlexboxで中央寄せした文字の位置を計測。指定なしの時点で文字の中心と容器の中心はぴったり一致(ズレ0.00px)text-box: trim-both cap alphabetic を当てると要素の高さは96px→36.77pxに縮むが、文字の中心はむしろ0.38pxずれたChrome 133・Safari 18.2 で対応。Firefox は web-features のデータに記載がなく、caniuse は 154 以降を対応として扱う「中央寄せすると文字が下にずれて見えるから text-box-trim で直す」という説明は、この計測では再現できなかった。行の高さが上下対称なら、Flexboxの中央寄せだけで文字も中央に来る

アンカーポジショニングの食い違いについて補足します。caniuse は主要ブラウザの実装状況を見て「対応済み」としていますが、web-features は position-visibility など周辺のサブ機能まで全エンジンに揃っているかを条件にしているため、判定が false のままになっています。どちらかが間違っているのではなく、判定の粒度が違うだけです。採用を検討する場合は、自分が使いたい値やプロパティ単位で対応表を確認してください。

もう1つ、古い記事でよく見る「レガシー環境では margin: autoposition、モダン環境では Flexbox / Grid」という使い分けも、いまは判断軸として機能しません。Flexbox は2018年3月、Grid は2020年4月の時点で主要ブラウザに出揃っています。2026年に「対応ブラウザの都合でFlexboxを避ける」判断はほぼ成立しません。選ぶ基準は対応状況ではなく、この記事の早見表のとおり「何を・どの軸で中央にしたいか」と「既存のレイアウトをどこまで変えてよいか」です。


検証環境と出典

本記事の数値は、記載のCSSをそのままiframeに流し込み、Chrome 150(macOS)getBoundingClientRect() を取得して計測したものです(計測日 2026年8月2日)。中央かどうかの判定は、記事中の診断スニペットと同じく「左右の余白の差、上下の余白の差がともに0.5px以内」を基準にしています。対応状況の数値は、同日に取得した web-features のデータセット(v3.34.2)に基づいています。


よくある質問(FAQ)

Q. margin: auto が効かないのはなぜですか?

通常フローのブロック要素は幅が親いっぱいに広がるため、widthmax-width を指定しないと左右に余白が生まれず中央に寄りません。ただしこれは通常フローに限った条件で、Flexboxやgridの子要素、inset: 0 を付けた絶対配置の要素なら、width を指定しなくても margin: auto だけで両軸中央になります(実測でflexの子は左152.94px/右152.93px、上88px/下88px)。

Q. place-items: center は Flexbox でも使えますか?

使えません。place-itemsalign-itemsjustify-items の一括指定ですが、justify-items が制御する justify-self は仕様上flexアイテムに適用されないため、Flexboxでは縦方向しか中央になりません。実測でも display: flex; place-items: center; は上下こそ中央(上80px/下80px)になるものの、横は左0px/右280pxのまま動きませんでした。Flexboxでは justify-content: center; align-items: center; と書いてください。

Q. place-items と place-content はどちらを使えばよいですか?

子要素が1つなら結果はほぼ同じですが、複数あると変わります。place-content: center は複数の要素をひとかたまりにして中央へ寄せ(実測で子2つが上72px/104pxの位置に隣接)、place-items: center は各要素をそれぞれのトラックの中で中央に置きます(同条件で上36px/140pxに分離)。カードを並べてまとめて中央に置きたいときは place-content です。

Q. Flexbox や Grid を使わずに上下中央にできますか?

できます。通常のブロック要素に align-content: center を指定するだけで縦方向の中央寄せが効きます(Chrome 123・Firefox 125・Safari 17.4 以降、Baseline newly available 2024年4月16日)。横方向の margin-inline: auto と組み合わせれば、display を変えずに上下左右の中央寄せが完成します(実測で左140px/右140px、上138px/下138px)。

Q. モーダルが画面中央に来ないのはなぜですか?

リセットCSSの * { margin: 0 } が原因のことがあります。<dialog> はブラウザ標準スタイルの inset: 0margin: auto によって中央に配置されるため、全称セレクタで margin を消すとモーダルが画面の左上に張り付きます(実測で左0px/上0px、算出 margin-left も 0px)。dialog { margin: auto; } を書き戻せば中央に戻ります。

Q. 画像を中央寄せするにはどうしますか?

img は初期状態がインラインレベルなので、display: block を足したうえで margin-inline: auto(または margin: 0 auto)を指定します(実測で親400px・画像100pxに対し左150px/右150px)。親に display: flex; justify-content: center; を指定する方法でも中央になりますが、親の text-align: center で寄せると同じ親の中のテキストもすべて中央寄せになる点に注意してください。

Q. vertical-align: middle で中央寄せできないのはなぜですか?

vertical-align はインライン要素とテーブルセルの中でしか有効ではなく、ブロック要素の垂直中央寄せには使えません。実測でも、高さ200pxの親に置いたブロック要素に vertical-align: middle を指定したところ、上0px/下140pxのまま一切動きませんでした。ブロック要素を垂直中央にしたい場合は Flexbox の align-items: center か、ブロックレイアウトの align-content: center を使ってください。

Q. 中央寄せが効いているかを確認する方法はありますか?

DevToolsのコンソールで対象要素と親要素の getBoundingClientRect() を取り、左右の余白の差と上下の余白の差を見てください。差がともに0.5px以内なら中央です。本記事の診断スニペットを貼れば、差の数値に加えて「親に高さが無い」「子が親と同じ幅」「自分がinline」といった原因の分類まで一度に出力されます。