フッターメニューやページ送りのナビゲーションで、リスト項目を横一列に並べて、しかも全体を真ん中に置きたい。私も何度もぶつかってきた場面です。ところが「margin: 0 auto;」や「text-align: center;」を素直に書いても、リスト全体がきれいに中央へ来てくれないことがあります。
うまくいかないのは、この2つの指定がそれぞれ別のものを動かしているからです。ulは何も指定しなければ幅が親いっぱいに広がるので、左右に振り分ける余りがありません。margin: 0 auto; が効くのは width や max-width で幅を決めたときだけで、幅が決まって初めて余りが生まれ、autoがそれを等分します。
もう一方の text-align: center; は、MDNの定義では「ブロック要素または表のセルボックス内におけるインラインレベルコンテンツ」を揃える指定です。ところが float: left; を当てたliは通常のフローから外れ、包含ブロックの左右どちらかに寄せられるので、この指定の対象になりません。つまり打ち手は3つです。並べ方そのものを中央に置ける仕組みへ変えるか、liを行の中に並ぶ形へ戻すか、floatのまま位置をずらして打ち消すか。
この記事では、その中央揃えを実現する方法を、昔ながらのfloatを使うやり方から、今なら第一候補になるFlexboxやGridまで整理して紹介します。今から新しく書くならFlexboxが一番ラクなので、まずはそこから始めます。
まず結論:今ならFlexboxが一番簡単
リストを横並びにして中央に置くだけなら、ul(リストを囲む親)に display: flex; と justify-content: center; を指定するだけで済みます。floatのように打ち消しの計算をする必要はありません。
共通で使うHTML
<div id="menu">
<ul>
<li><a href="#">メニュー1</a></li>
<li><a href="#">メニュー2</a></li>
<li><a href="#">メニュー3</a></li>
<li><a href="#">メニュー4</a></li>
<li><a href="#">メニュー5</a></li>
</ul>
</div>
以下ではこのHTMLを共通して使います。
Flexboxで中央揃えする(推奨)
CSSはこれだけです。
#menu ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
justify-content: center;
}
ulを display: flex; にすると、中のli要素は自動的に横並びになります。float: left; を書く必要はありません。そのうえで justify-content: center; を指定すると、並んだ項目のかたまりが親要素の横方向(主軸)の中央に配置されます。MDNでも justify-content: center は「アイテムを主軸の中央に寄せてまとめて配置する」値と説明されています。
項目が多くて1行に収まらないときは、次のように折り返しを許可しておくと安心です。
#menu ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
flex-wrap: wrap; を付けると、幅に入りきらない項目が次の行へ折り返されます。横スクロールバーが出てしまう心配もなくなります。上下方向の位置も揃えたいときは align-items: center; を足せば、縦方向(交差軸)の中央にもそろいます。
項目の間隔は gap で空ける
項目どうしに隙間がほしいときは、liに margin を振るより gap のほうが素直です。gap はGrid専用ではなく、フレックスコンテナーでも同じように使えます。
#menu ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1rem;
}
gap が隙間を作るのは項目と項目の間だけで、両端には余白が付きません。marginで同じことをすると最後の項目の右側にも余白が残り、そのぶん全体の中心が左へずれます。li:last-child で打ち消す一手間も要りません。折り返しを許可している場合は、行と行の間にも同じ値の隙間が入ります。行と列で値を変えたいなら、row-gap と column-gap に分けて書いてください。
なお、見えている隙間が指定した値と違うこともあります。MDNは、マージンやパディング、分配配置によって gap が決めた値より要素間が広がるかもしれない、と注記しています。間隔が合わないと感じたら、まずli側にmarginが残っていないかを確かめてください。
Gridで中央揃えする
Gridでも同じことができます。gap の書き方は先ほどのFlexboxと同じです。
#menu ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
grid-auto-flow: column;
justify-content: center;
gap: 10px;
}
grid-auto-flow: column; で項目を横方向に並べ、justify-content: center; でグリッド全体を中央へ寄せています。行と列に広げたときは、gap: 10px; がそのまま行間の隙間にもなります。横一列のメニュー程度ならFlexboxで十分ですが、行と列を組み合わせたレイアウトに発展させたいときはGridが向いています。
liをinline-blockにすると text-align が効く
liを display: inline-block; にすると、liは行の中に並ぶ扱いに戻ります。text-align の対象になるので、親に text-align: center; と書くだけで中央にそろいます。
#menu ul {
list-style: none;
padding: 0;
margin: 0;
text-align: center;
}
#menu li {
display: inline-block;
}
floatを使わないので打ち消しの計算が要らず、冒頭で書いた text-align: center; がそのまま通るのが利点です。ただし、HTMLの改行やインデントが半角スペース1つぶんの隙間として項目の間に出ます。消すにはliのタグを詰めて書くか、親の font-size を0にして子で戻すといった小細工が必要です。新しく書くなら、先に挙げたFlexboxかGridのほうが素直です。
【レガシー】floatで中央揃えする方法
ここからは、FlexboxやGridが普及する前によく使われていた、floatによる中央揃えです。今は第一候補ではありませんが、仕組みとして今も動きますし、古いコードを読むときに知っておくと役立ちます。
floatで横並びにしたリストは、ul全体をそのまま中央に置こうとしてもうまくいきません。そこで、ul要素を右に50%動かし、li要素を左に50%戻すというテクニックを使います。
#menu { position: relative; overflow: hidden; }
#menu ul { position: relative; float: left; left: 50%; }
#menu li { position: relative; float: left; left: -50%; }
それぞれの役割はこうです。
- #menu に
position: relative;を付けて、内側の要素の位置決めの基準にします。overflow: hidden;は、ズレによって横スクロールバーが出るのを防ぐための対策です。 - #menu ul に
float: left;とleft: 50%;を指定し、リスト全体を右へ50%移動させます。 - #menu li に
left: -50%;を指定して、各項目を左へ50%戻します。結果として、ちょうど中央にそろいます。
ulを右に50%、liを左に50%と、逆方向に同じだけ動かすことで打ち消し合い、全体が中央に来るという理屈です。left: -50%; は right: 50%; と書いても同じ意味なので、わかりやすい方を使えば大丈夫です。
どれを選べばいい?
今から新しく書くなら、迷わずFlexboxをおすすめします。コードが短く、意図も読み取りやすく、折り返しや縦の中央揃えにも素直に対応できます。行列のあるレイアウトに広げたいならGrid。すでにinline-blockで組んである場所なら、text-align: center; を足すだけで済みます。そして、既存のfloat中心のコードを触っていて、周りに合わせたいときや、そのまま手を入れたいときはfloatの手法、という使い分けが現実的です。
まとめ
floatで横並びにしたリストを中央揃えする方法を、レガシーな手法と現代的な手法の両方で見てきました。ポイントを整理します。
- 今ならFlexbox:ul に
display: flex;とjustify-content: center;だけ。折り返すならflex-wrap: wrap;を追加。 - 行列に広げたいならGrid:
display: grid;とgapで間隔もまとめて管理。 - inline-block:liを
display: inline-block;にして親にtext-align: center;。項目の間に隙間が出る点だけ注意。 - floatは ul を right へ50%、li を left へ50%で打ち消して中央に。今も動くが位置づけはレガシー。
既存のfloatをFlexboxへ置き換えるときは、打ち消し用の指定も一緒に外せます。#menu { overflow: hidden; } やclearfixは、floatで親の高さが潰れるのを防ぐためのものなので、floatをやめた時点で役目が終わります。残したままだと、なぜ効いているのか分からない指定になって、次に触るときに手が止まります。
置き換えたあとに確かめるのは2か所です。項目が増えたときに折り返すか(flex-wrap: wrap;)、そして左右の余白が同じか(liに margin が残っていないか)。この2つがそろっていれば、画面幅を変えても中央からずれません。
手元のコードの事情に合わせて、一番ラクに書ける方法を選んでください。