5 ポイント 投稿者 GN⁺ 2024-02-14 | 3件のコメント | WhatsAppで共有
  • CSSの中央揃えはもはや単一のテクニックではなく、要素が文書フロー内にあるか・浮いているか・複数あるかによって、Flow、Flexbox、Positioned layout、CSS Grid、text-align から選ぶ問題である
  • 単一要素を水平方向の中央に置くときは、max-width: fit-content で幅を制限し margin-inline: auto を適用する Flow layout の方法が、兄弟要素への影響が少ない
  • Flexboxは justify-content: centeralign-items: center だけで、単一・複数の子要素を水平・垂直方向の中央に配置でき、子要素がはみ出しても 対称的にオーバーフロー する
  • モーダル・バナーのような浮いたUIには、position: fixedinset: 0、サイズ制限、margin: auto の組み合わせが適しており、CSS Gridは短い記法と 重ねて配置する 用途に強い
  • テキスト自体はレイアウトの整列ではなく text-align: center が必要で、Flow layout の align-content サポートが広がれば、単純な垂直中央揃えのために Flexbox や Grid に切り替える場面は減る可能性がある

Flow layoutでauto marginを使って水平方向の中央揃え

  • 古くからある戦略のひとつは、要素の幅を制限したうえで左右のマージンを auto にする方法である
.element {
  max-width: fit-content;
  margin-left: auto;
  margin-right: auto;
}
  • Flow layout の要素はデフォルトで横方向の空間を埋めるため、中央に置くにはまず 幅の制限 が必要になる
  • fit-content は要素がコンテンツを包み込むようにし、widthheight のようにコンテンツサイズによって決まるようにする
  • width ではなく max-width を使うと最大サイズだけを制限するため、コンテナが狭くなったときに要素も一緒に縮められる
  • margin-left: auto だけなら余った空間は左マージンに入り、左右両方のマージンを auto にすると余白が均等に分配されて要素が中央に置かれる
.element {
  max-width: fit-content;
  margin-inline: auto;
}
  • margin-inlinemargin-leftmargin-right に同じ値を設定するモダンな方法で、ブラウザ対応 も良い
  • margin-inline論理プロパティ(logical properties) の一部であり、左右ではなく書字方向の inline 軸を基準に動作する
    • 左から右に書く言語でも右から左に書く言語でも、正しい側にマージンを適用できる
  • この方法は、ブログ記事中の画像のように 単一の子要素だけを中央揃え し、兄弟要素には影響を与えたくない場合に有用である

Flexboxで単一・複数の子要素を中央揃え

  • Flexbox は主軸に沿って複数の項目を配置するのに強いレイアウトモードで、中央揃えにもよく使われる
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}
  • justify-content: centeralign-items: center を併用すると、子要素を水平・垂直方向の中央に置ける
  • 子要素がコンテナに収まらなくても整列は維持され、はみ出す場合でも 対称的にオーバーフロー する
  • 複数の子要素も中央揃えでき、flex-direction で積み重なる方向を制御する
.container {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 4px;
}
  • 単一または複数の子要素に幅広く適用できる 基本の選択肢 として使いやすい

Positioned layoutで浮いたUIを中央揃え

  • モーダル、プロンプト、バナーのように通常の文書フローから外れて上に浮く必要がある要素は、Positioned layout で扱える
.element {
  position: fixed;
  inset: 0px;
  width: 12rem;
  height: 5rem;
  max-width: 100vw;
  max-height: 100dvh;
  margin: auto;
}
  • position: fixed は要素を viewport に固定し、inset: 0pxtopleftrightbottom をすべて 0px に設定する
  • inset: 0px だけだと要素は viewport 全体を埋めようとするため、widthheightmax-widthmax-height でサイズを制限する必要がある
  • この組み合わせは、意図的に成立しない条件を作り出す
    • 要素が左と右の両方から 0px 離れていながら、同時に 12rem の幅を持つことはできない
    • CSS レンダリングエンジンは width の制約を優先し、言語方向に応じて片側に寄せる形でその緊張を解消する
  • ここに margin: auto を入れると、ブラウザの解消方法が変わり、要素が 水平・垂直方向の中央 に置かれる
  • 必要な4つの条件は、position: fixedinset: 0px、制限された幅と高さ、margin: auto である
  • 下部バナーのように一方向だけ中央揃え

    .element {
      position: fixed;
      left: 0px;
      right: 0px;
      bottom: 8px;
      width: 12rem;
      max-width: calc(
        100vw - 8px * 2
      );
      margin-inline: auto;
    }
    
    • top: 0px を省略すると垂直方向の成立しない条件がなくなり、要素は下部に固定される
    • calc(100vw - 8px * 2) は viewport の左右に余白を残すよう最大幅を制限する
    • margin-inline: auto は、水平方向を中央揃えしたい意図をより正確に表している
  • サイズが分からない要素

    .element {
      position: fixed;
      inset: 0;
      width: fit-content;
      height: fit-content;
      margin: auto;
    }
    
    • 要素サイズを事前に把握できない場合は、width: fit-contentheight: fit-content でコンテンツを包ませられる
    • max-width: 60vw のような制限を追加することもできるが必須ではなく、要素は viewport 内に収まる
  • 意図的に少しずらした中央

    • bottom: 48px のように片側の inset 値を調整すると、要素は指定値の半分だけ移動する
    • bottom: 48px なら要素は上に 24px 移動する
    • これは要素が上下の境界のあいだにある 仮想ボックス の中で中央に吊られているためである
    • transform: translateY(-48px) を使えば、要素を正確に 48px 上へ移動できる
    • bottom オフセット方式なら、transform プロパティを後のアニメーションや導入エフェクト用に残しておける

CSS Gridで短く中央揃えし、重ねて配置する

  • CSS Grid で最も短い中央揃えコードは、display: gridplace-content: center の組み合わせである
.container {
  display: grid;
  place-content: center;
}
  • place-contentjustify-contentalign-content の短縮形で、行と列に同じ値を適用する

  • この設定によって、親コンテナの中央に 1×1 Grid セルが作られる

  • Flexboxとの違い

    • 見た目は Flexbox と似ていても、CSS Grid はまったく異なるレイアウトアルゴリズムを使う
    • 子要素に width: 50%height: 50% を与えると違いが現れる
    • Flexbox ではパーセンテージは親 .container 基準で計算される
    • CSS Grid ではパーセンテージは Grid セル 基準で計算される
    • grid-template-columnsgrid-template-rows を指定しない場合、Grid トラックはコンテンツ基準でサイズ計算されるため、要素が想定より小さくなることがある
    • このような場合は Grid を修正するために CSS を追加できるが、単純な中央揃えなら Flexbox のほうが簡単なこともある
  • 複数要素を同じ位置に重ねて配置

    .container {
      display: grid;
      place-content: center;
    }
    
    .element {
      grid-row: 1;
      grid-column: 1;
    }
    
    • CSS Grid は複数の子要素を同じセルに配置できる
    • すべての .elementgrid-row: 1grid-column: 1 を与えると、要素同士が同じ Grid 空間を共有し、前後に重なって積み上がる
    • 子要素のサイズが互いに異なっていても機能する
    .container {
      display: grid;
      place-content: center;
      place-items: center;
    }
    
    .element {
      grid-row: 1;
      grid-column: 1;
    }
    
    • サイズの異なる子要素を中央で重ねたい場合は、追加で place-items: center が必要である
    • place-itemsjustify-itemsalign-items の短縮形で、Grid セル内での画像の整列を制御する
    • このプロパティがないと Grid セル自体は中央にあっても、セル内の画像は左上に積み重なる
    • CSS Grid をさらに深く知りたいなら An Interactive Guide to CSS Grid を参照できる

テキストはtext-alignで別途整列する

  • テキストは CSS では別個に扱う必要があり、Flexbox のようなレイアウト手法は個々の文字を整列しない
  • Flexbox で段落を中央に置くと、段落ブロック は中央に来ても、段落内の文字は左揃えのまま残る
  • テキスト自体を中央揃えするには text-align: center を使う必要がある
.container {
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

Flow layoutの未来: align-content

  • Flow layout では水平方向の中央揃えは auto margin で可能だが、垂直方向の中央揃えにはこれまで Flexbox や Grid のような別のレイアウトモードが必要だった
  • 2024年初頭時点でブラウザベンダーは、Flow layout における align-content を実装中である
  • この新しい挙動はコンテンツの block 方向の整列 を制御し、当時は Chrome Canary のフラグ付き機能と Safari Technical Preview でのみ利用できた
  • 例のデモは実際の Flow layout の挙動ではなく、Chrome Canary と Safari TP の動作を確認したうえで Flexbox で再現したものである
  • この機能は新しいUIを生み出すものではないが、単純な中央揃えのために別のレイアウトモードへ切り替える必要性を減らせる可能性がある

状況別の選び方

  • 単一要素を兄弟要素に影響を与えず水平方向に中央揃えしたいなら、Flow layout の auto margin 戦略を使う
  • モーダルやバナーのような浮いたUIは、Positioned layout と auto margin で中央に配置する
  • 複数要素を同じ位置に重ねて中央に積み上げたいなら、CSS Grid が適している
  • テキストを中央揃えしたいなら text-align を使い、ほかの中央揃え手法と組み合わせられる
  • それ以外の大半の状況では、Flexbox が最も汎用的な選択肢である
    • 単一または複数の子要素を扱える
    • 水平・垂直方向の中央揃えの両方が可能である
    • 子要素がコンテナ内にあっても、はみ出していても使える

3件のコメント

 
v08zbv8fvlkjasdflkj 2024-02-15

そういえば、GeekNewsも記事が中央揃えになっていないのが急に気になりますね(泣)笑

 
joyfui 2024-02-14

place-items: center; を愛用していますが、方法はほかにもいろいろあるんですね。

 
GN⁺ 2024-02-14
Hacker Newsのコメント
  • 他のコメントがコメント自体を論評しているので、私も口を挟むと、CSS中央揃えミームはたいてい「ある要素を別の要素のど真ん中に置く方法」を意味していると思う
    実装の観点から見て中央揃えが難しく、複数の意味を持ちうるという話はその通りだが、GeoCities や AngelFire の世代にとっては、HTML で 90 年代にも 600x600 の黄色いボックスのど真ん中に hello を問題なく入れられたので、納得しづらかった
    より良いとされた新しい道具が、すでにできていた標準的な作業をこなせないのだから腹が立ち、だから 2000 年代後半まで テーブルレイアウトを使い続けていた
    CSS は好きだが、これは一種のストックホルム症候群なのかもしれない
    valign は Chromium ではなくても動くので驚いたが、最近の変化なのかは分からない

    • 言うとおり、つまり 600x600 の黄色いボックスのど真ん中に hello を入れることは、CSS の最初のバージョンから可能だった。たとえば HTML の valign 属性は、inlineinline-blocktable-cell ボックスの vertical-align CSS プロパティに対応している
      ただ経験上、テーブルだけを使おうとロマンチックに語ったり、CSS は制限だらけで混乱していると不満を言ったりする人のかなり多くは、実際に CSS がどう動くのかを学ぼうとする努力をほとんどしていなかった。筆者は少なくともその点を自覚している
    • Firefox でも "valign" 属性なしで動作する。ただし固定レイアウトなしでテーブルを使う場合、主要 3 ブラウザ間で微妙な違いを常に見てきたので、一般的には 自動レイアウトの挙動には依存しないだろう
  • 良い記事で、名目上は技術系の読者層であることを考えると、ここの反応にはかなり驚いた。自動ページレイアウトと組版は本当に難しく、実際に博士論文のテーマになるほどだ[1]
    その複雑さを「自分の意図どおりにしてくれ」のような単純な表現で抽象化できると期待するのは現実的ではない
    Gwern Branwen のウェブサイト[2]を見ると芸術に近いが、要点はまず欲しい見た目を決め、そのスタイルの中で文章が表現可能になるよう制約をかけることだ
    1995 年に「ウェブ初のゴルフ雑誌」スタートアップ[3]に参加して以来、ウェブページレイアウトを見てきたが、Zen Garden と A List Apart のメーリングリスト / ウェブサイト[4]のおかげで、さまざまな出力環境でうまく見えるウェブコンテンツを作ることがどれほど難しいかを理解するようになった
    意味的なコンテンツを画面、紙、有限の平面へ移すことは、もともとの空間から目的地の空間にある規則の集合への 写像または射影であり、その規則には物理的制約、ブラウザソフトウェアの制約、各ブラウザ固有の挙動がすべて含まれる
    だから CSS は「最初からウェブページを作ろう」とする人にはめちゃくちゃに見えるが、実際にはできることを妨げる制約というより、選択肢が多すぎる側に近い
    [1] https://scholar.google.com/scholar?hl=en&as_sdt=0%2C5&q=thes...
    [2] https://gwern.net/
    [3] Golfweb という名前で、最終的には CBS Sports の一部になったようだ
    [4] https://www.alistapart.com

    • ウェブレイアウト歴は 1998 年からなので 3 年ほど遅いが、関連する経験全体を通しても Every Layout の資料[1]ほど優れたものはまだ見たことがない。強く勧めたい
      [1] https://every-layout.dev/rudiments/boxes/
    • CSS の問題はほとんど完全に 自ら招いた複雑さだ。レイアウトが難しいのは確かだが、なぜ今のようなモデルを目指してさらに難しくしたのか疑問だ
      とくに、あらゆるページに当てはまる一つの大きなモデルを志向し、各ページごとに自動レイアウトを毎回再計算しようとするシーシュポス的な目標がある。これにあらゆるウィンドウサイズを対象にするという目標まで加わると、なぜそれが可能だと思ったのか分からない
    • CSS アートをもっと見てほしくて、このリンクを貼らずにはいられなかった
      https://css-art.com/the-girl-with-a-p-e-a-r-l-css-earring/
      中央揃えされた div がいくつ含まれているのかは分からない
    • ここ数日、フローベースのレイアウトとページ分割を Flexbox ベースのレイアウトシステムに無理やり押し込もうとしていたが、レイアウトと組版が確かに難しいことを再確認した
      とくに列ごとにサイズの異なるテキストやオブジェクトが入っている表で、要素をいつどうやって次のページへ送るかを決めるのは、よいヒューリスティクスを選ぶ厄介な作業だ
    • これが自己誘発的な問題なのか、それとも本質的に難しい研究課題なのか、どう見分けられるのか分からない。ウェブ開発に入る前は「レイアウトは難しい」と考えたことはなく、その頃にもスクロール可能でサイズ変更可能なウィンドウはあった
      custom appkit、GTK コントロール、非公開の Lua ベースのツールキットでも、コンテンツの中央揃えや要素の折り返し・整列は大したことではなかったのに、ウェブでは何を見落としているのか気になる
      「選択肢が豊富なだけ」という言い方は、ずっと前に葬られた TMTOWTDI にも少し似て聞こえる
  • 素晴らしい記事で、インタラクティブな要素がとくに良い。数年前に CSS の位置指定と中央揃えを理解するうえで大いに役立ったのは ボックスモデルを読んだことだった
    ボックスモデルを理解すると DOM 内のフローを判断する助けになり、displayposition の CSS プロパティも位置指定を学ぶうえで基本になる。MDN のドキュメントはよくできている
    https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_...
    https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layou...

  • 「中央揃えの方法」は CSS の古典的な質問であり、それが目の前に見えているほど明白ではないという事実自体が多くを物語っている。CSS は 混沌とした寄せ集め に近く、単一の委員会ではなく複数の委員会が同時に設計した流し台式の詰め合わせだ
    実際のリリースという概念はずっと前に放棄されており、現在の CSS の状態は、変化し続ける個別モジュールの状態を寄せ集めたものに近い。これはソフトウェアを開発するやり方ではなく、実際、何かを作るうえで良いやり方でもない

    • 同意もするし反対もする。大きな人間集団は本来このように遅く混乱しながら動くもので、猫追いに近い
      Web とその技術群が集団としてどこへ向かっているのかも明確ではないため、失敗した実験や不一致が多く生まれるのは避けられない。明確な目標と道筋がある、よく計画された工学プロジェクトよりもはるかに広い範囲なのだから
    • 中央揃えの質問が頻繁に出るのは、学ぶ側からすると最初に尋ねるのがあまりにも自然な質問だからだと思う
      Web ページを望む見た目にしようとする人が最初に学ぶのは、たいてい文字サイズ、色、背景色、配置であり、配置を除けば残りは CSS 以前のやり方とほぼ 1:1 に対応している
      CSS 以前は、コンテンツを中央に置きたければ単にタグに入れればよく、テキストであれ div、表、ボタンのような HTML オブジェクトであれ関係なかった。多くの人は CSS も昔のように インライン要素とブロック要素の区別なく 動くことを期待していたが、CSS がその先入観に合わなかったため、こうした質問が生まれたのだ
  • この記事は本当に良く、特にインタラクションのしかたが素晴らしい。かなり前から、ほぼいつも望んだ結果をくれたツールもある
    http://howtocenterincss.com

  • CSS がコンテンツを中央に置くテーブル並みに使える解決策を出すまでに何十年もかかったが、その間 レイアウトにテーブルを使うこと は非難されていた

    • HTML テーブルはモバイル画面でうまく折り返されない。レイアウトをテーブルで作ると横スクロールバーが出る可能性が高く、モバイル対応のために書き直しが必要になることもあるので、データ表でないなら CSS フレームワークのほうがたいてい安全だ
      HTML テーブルはアクセシビリティのために少なくとも `` のような処理が必要だ
      https://developer.mozilla.org/en-US/docs/Learn/HTML/Tables/A...
      CSS Grid Layout の資料も参考になる
      https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_la...
      Firefox DevTools > INTRODUCTION TO CSS GRID LAYOUT: https://mozilladevelopers.github.io/playground/css-grid/
      CSS Grid Garden: https://cssgridgarden.com/
      MDN > "Relationship of grid layout to other layout methods": https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_la...
      MDN: "Box alignment in grid layout": https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_la...
    • 表ではないデータをテーブルで表現するのは セマンティックではなく、アクセシビリティも損なう
      Web 開発にはコンテンツがページのどこに置かれるか以上の要素があり、だからこそ良い Web 開発は難しいのだ
    • その通りで、当時を覚えている。div と CSS の利点はヒップスター的な評判で、欠点は DIV スープ だった
      当時の CSS は、人々がやろうとしていたことに対して信じられないほど不向きだった。文書の書式設定用に設計されていて、Web アプリや画面レイアウト用に設計されたものではなかったからだと思う
      一方で table の利点は、実際に動作することだった
    • 当時は テーブルを使う方法 が最も堅牢だと感じていた
  • ここにいる多くの人と同じく、CSS は完全な災厄だと思う。核心的な問題は、スタイル指定が絶えず互いを 上書きしたり、まったく効果がないまま静かに失敗したりすることだ

  • 例のひとつにあったクッキー案内が残酷なほど正直で良かった
    「私たちはあなたの個人情報データを大切にしています。ブラウジング体験を向上させるため、このデータを広告主に販売するクッキーを使用します。これは非常に価値があります」

  • レイアウトにテーブルを使ってきた歴史から学べることがあるのは興味深い。テーブルには境界線、パディング、列に並んだセルベースのレイアウトがあり、拡張するとテーブルとセルの周囲には余白、つまりマージンも必要になる
    テーブルはレイアウトにおいて長く確立された要素であり、実際、すべての要素がある程度 テーブルセルのように振る舞うべきだ という知恵を含んでいた
    要素はボックスモデルに従うべきで、これはタイポグラフィを扱う人にはかなり自明だが、同時に列に並ぶべきだという点はそれほど明白ではなく、Grid layout や Bootstrap の基盤になっている
    レイアウト問題に出会ってテーブルで解決したあと、テーブルの一部の特性は持つが全部ではない新機能が必要だと気づくのは自然な進化だ
    CSS はこれを見いだしたが、不思議なことに、ワードプロセッサのような一部のシステムは要素をボックスモデルの下に統合できなかった

  • 「なぜいまだにこんなに難しいのか」という不満は、かなり的外れに感じられる。記事でも述べられているように、Flexbox は単純なあらゆるケースの中央揃えを直感的に解決する。
    Flexbox で解決できないなら、それは単に中央揃えをしているだけではなく、より複雑なことをしているのであって、実装がとても単純であることを期待するのは適切ではない

    • 長くやってきた立場からすると、Flexbox 以前は難しかったし、Flexbox が 100% サポートされていなかった時期にも、ブラウザの利用状況を追い続けながら使えるかどうかを判断しなければならず大変だった。
      今では方法が多すぎて、複雑さに圧倒される。新しく作る場合より古いコードを直す場合のほうが多く、なぜ CSS が特定の書き方になっているのか、どんなエッジケースが壊れるのか、直してよいのか、単純でないときに複数の解法のうちどれを選ぶべきかを考えなければならない。
      記事をざっと見ても直感的ではない。Flexbox でも横方向の設定は justify-content、縦方向の設定は align-items だが、CSS のプロパティ名は多すぎて恣意的で、もううまく覚えられない。
      結局のところ違いは、単純で直感的かつ信頼できるビルディングブロックで複雑な解法を組み立てるのか、それとも一部が重なり合い、毎回検索し続けなければならない複雑なビルディングブロックで複雑な解法を組み立てるのか、という点にある。
      Go や Python は前者に近く、CSS は後者に近い
    • Flexbox は、私がいつも CSS にこうなってほしいと願っていた姿そのもので、長い間そうではなかったのに、ある日そうなり、Flexbox のないブラウザ対応を捨てられるようになった。ほとんど CSS の最終形 のように感じられる。
      人々が Bootstrap のグリッドシステムを好んでいたのには理由があり、Flexbox はそれらすべてと、それ以上のことをブラウザ内でそのまま実現してくれる。どれほど気に入っているかは誇張しようがないほどだ
    • かつては特定のケースではそれなりに難しかったが、この10年ほどはすでに解決済みの問題だ。いまだに CSS で div を中央揃えするのが錬金術とロケット科学の中間のようなものだと語る人がいる。
      Web 開発のほかの部分ほど CSS の変化を追っていないのに、そういう断言だけは気軽にする姿勢が表れている
    • しかも Flexbox は 10年以上にわたって広くサポートされてきた。ここのコメントの流れはかなり興味深い
    • 本当にその通りだ。Flexbox と格闘しているときは、一歩引いて一段階ずつ解いていくと役に立つ。
      外側から内側へ、親要素から子要素へとたどると、ずっと簡単になる。技術は必要だが、基本的には 弾性代数 に近い