HTMLとCSSで、テキストや画像を縦方向(上下方向)に中央寄せ(センタリング)したい事があります。
この課題は簡単そうに見えて、意外と厄介です。実際のところ、実現方法にはいくつかの選択肢がありますが、いずれも、HTML、CSSの初学者にとってはちょっとだけトリッキーです。さっそく見ていきます。
目次
【はじめに】HTML とCSS に関する基礎知識
CSSでの中央寄せ方法を考える上で、まず最初に知っておかなければいけないのは、HTML要素における「インライン」と「ブロック」の考え方です。
HTMLでは、テキスト(文字列)のような、文書に流れ込むように配置される要素は「インラインレベル」の要素と呼ばれます。これらは、要素の横幅を満たすように配置される「ブロックレベル」の要素と区別されます。
デフォルトでインラインレベルの要素なのは、例えば、<a>タグや<span>タグです。逆にブロックレベルなのは、<div>, <h1>, <p> などはよく利用するタグだと思います。このようなデフォルトでの状態も、CSS「display」プロパティを指定することで「display: block」と「display: inline」と指定して、変更することもできます。
インラインとブロックの概念の詳細は、この記事末尾の補足セクションに解説を加えましたので、ぜひご覧ください。
CSSによるテキスト(=インライン要素)の上下左右の中央寄せ
テキストの横(左右)方向の中央寄せ
インライン要素の横(左右)の中央寄せは、インラインレベルの対象要素の親要素に対してCSSプロパティ「text-align: center」を適応します。
「text-align」自体はブロックレベルの要素に対して、その要素が内包するインライン要素のテキスト寄せ方に関する振る舞いを定めるためのプロパティです。(※要素に内包されたテキストはインラインレベルとして振る舞います。すなわちブロック要素の中にタグに囲まれていないテキストだけがあれば、テキストはインラインの振る舞いとなります。)
<div class="container">
左右に中央寄せ。
</div>
<style>
.container{
text-align:center;
background-color:#ffe2e0;
}
</style>
テキストの縦(上下)方向の中央寄せ
縦(上下)方向の中央揃えは、1行のテキストか、2行のテキストかで、複雑さが変わります。
1行のテキストの場合
CSSで、line-heightプロパティは、1行あたりの高さを大きく定めれば、内包されたテキストは縦方向のおおよそ中央付近に配置されます。これは基本的な仕様ですので、あまり細かい説明は不要かもしれませんね。
<div class="container">
1行のテキストで縦の中央寄せ。
</div>
<style>
.container{
line-height:200px;
text-align:center;
background-color:#fff2fa;
}
</style>
CSSの「line-height」プロパティは、その値にpxやpt値、もしくは、%や少数などの割合を指定できます。割合を指定すれば、font-sizeプロパティで指定されるフォントサイズに対する割合として解釈されます。上記のように、line-heightの値を極端に大きくすることで、自動的に内部のテキストが縦方向の中央寄せに配置されるというわけです。
ちなみに、通常のウェブサイトでは、line-height は1.2〜2程度の値が読みやすい範囲です。ブラウザ(Chrome)のデフォルトは「normal」というキーワードで指定され、その具体的な値はおおよそ1.2程度です。
太〜い1行、ということだね。
複数行のテキストの場合
2行以上のテキストの縦方向の中央寄せは少しトリッキーで、直感的には理解し難いかもしれません。実際の所、複数行のテキストのセンタリングにはいくつかの選択肢があります。下記に紹介する方法はいずれも「vertical-align: middle」というスタイル指定を利用しますが、アプローチが少し違います。
[方法1] 「テーブルセル」作戦
これも一般的な方法で、CSSの「display:table-cell」を使います。
仕組みとしては上述のインラインブロックと同じで、「display: table-cell」の子要素には「vertical-align:middle」が有効ですので、これによって上下に中央寄せします。「display:table-cell」は、tableの中のみで有効ですから、親要素にもまた「display:table」の指定が必要です。
見た目は全然テーブル(表)ではないのですが、CSSには「table」と書かれているという、若干の気持ち悪さが残りらなくも無いですが、スタイル(=表現)の問題だけですので、まあ気にしなくてもよいでしょう。
<div class="container">
<span class="target">テーブルセルは<br>vertical-align可能。</span>
</div>
<style>
.container{
display:table;
width:100%;
height:300px;
background-color:#eef;
text-align:center;
}
.container .target{
display:table-cell;
vertical-align:middle;
}
</style>
特に親要素の「display: table」は「width: auto」の振る舞いが、「display: block」のときと異なりますので、width値を宜しく設定するようにして下さい。
HTMLでは、table 要素は表示のルールが変わることをうまく利用しているんだね。
[方法2]「 インラインブロック」化する
こちらはややトリッキーですが、覚えるとおすすめの方法です。
displayプロパティの「inline-block」を利用します。CSSの、inline-blockプロパティは、2017年現在では、ほとんどのブラウザで完璧にサポートされていますので、恐れる必要はありません。
<div class="container">
<span class="target">2行以上の<br>テキストでも<br>自動的に中央付近に。</span>
</div>
<style>
.container{
line-height:300px;
background-color:#fec;
text-align:center;
}
.container .target{
display:inline-block;
vertical-align: middle;
line-height:normal;
}
</style>
対象対象のインライン要素(.target)の親要素(.container)で「line-height:300px」と高さを固定することで、内包される対象は自動的にその行内で、高さ方向の中央付近に配置されます。
ポイントは、その対象要素(.target)が、ブロック(正確にはインラインブロック)レベルであり、そこに line-heightの値を小さく設定している点です。上記は「normal」キーワード(ブラウザのデフォルト値)に指定していますが、お好みの数値で構いません。これにより、対象要素は自然な行の高さの複数行を実現しつつ、その要素自体は親の高さに対して、中央付近に配置できるのです。
ちなみに、「vertical-align」プロパティの指定が有効な要素には、display:inline、display:inline-block、display:table-cell などがあります。
逆に、display:block である要素はこの vertical-align プロパティの適応外ですので、このことを知らないとブロック要素に対して「あれ〜、vertical-align: middleにしているのに、なんで上下にセンタリングされないんだろ〜?」と時間を浪費してしまいがちです。vertical-alignは、「親要素の行に対する自身の縦方向の配置)」を決めるものです。
vertical-align にはそんな決まりがあったんだね・・・。
CSS「vertical-align」プロパティについて
HTMLにおいて、「行」に配置されたテキストにおいて、厳密に「縦方向の中央位置とはどこか?」の話をすると、かなり話が細かくなるのですが、少しだけ触れると「vertical-align: middle」は「その要素の縦方向の中央と、ベースラインの高さに、x-heightの半分の高さを加えた位置と合わせる」と定義されています。
参考まで、フォントには「x-height」と呼ばれる高さがあります。これは「英字フォントの小文字の高さ」であり、フォントデータ内で定義されます。
「vertical-align: middle」の定義である「baselineにx-heightの高さの半分を加えた位置(下図赤線)」は、その要素自体の縦方向の中央線と必ずしも一致しません。(フォントデータ次第です。)
これは「アルファベット文字の(見た目的な)中央」と要素を揃えて見せるための計算方法ですが、要素に指定されたフォントサイズが大きければ大きいほど「要素の中央線からのズレ」は大きく見えます。状況によっては、このずれが問題になることもあるでしょう。
Mozila Developer Networkのページで、CSSプロパティ「vertical-align」の詳細な定義に言及しています。
CSSによるブロック要素の上下左右の中央寄せ
ここからは、ブロック要素の中央寄せ方法です。インラインと幾分勝手が違いますので、ご注意下さいね。
5種類のスタイルの指定方法に分けて解説します。
1「絶対配置 + 自動マージン」を使った上下左右の中央寄せ
ブロックレベルの要素の中央寄せで、最も直感的なのは「position:absolute」を使った方法です。このプロパティと「margin:auto」を組み合わせれば、自動的に上下、もしくは左右がそれぞれのバランスを取るようにマージンが自動計算されます。下記の例をご覧ください。
対象となる div がデフォルトでブロックレベルですが、span, img, a, などのインライン要素も「display:block」でブロック化すれば同じ方法が適応できます。
<div class="container">
<div class="target">このブロックは中央に揃えました。</div>
</div>
<style>
.container {
height: 300px;
background-color: #def;
position: relative;
}
.container .target {
height:100px;
width: 200px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color:rgba(255, 255, 255, 0.6);
}
</style>
絶対配置の要素が自分の座標の基準値を見つけられるよう、親要素のpositionを、relative, absolute, fixed など、initial以外の値となるようにして下さい。また、対象要素の高さを明示的に固定してやる必要があります。(上記において、height: auto(初期値)では、親要素の上下に張り付くように対象の高さが自動計算されてしまうでしょう。)
margin: auto の特性をうまく利用した方法だね。
中央寄せしたブロックの高さは自動化できるの?
対象がブロックレベル要素のとき、その高さを自動的に最小の値に最適化する事は、絶対配置方式ではできません。もしそのような場合は、下記のいずれかの方法をつかう必要があります。
- 対象をインラインブロックにする対応す(前述のインライン方式です)
- flexboxを使う(このセクションで後述します)
また、対象要素の「アクペクト比(縦横比)」を指定したり、画像のアスペクト比を固定したい時は、このような方法もあります。ご参考まで。
2「絶対配置 + 負のマージン」での上下左右の中央寄せ
対象要素が絶対配置される際の基準点を、要素のマージン値を負の値にすることで、ずらす手法です。マージン値を要素の高さ、要素の幅のちょうど半分の値にすると、上下左右それぞれ中央に配置されます。
<div class="container">
<div class="target">このブロックは中央に揃えました。</div>
</div>
<style>
.container {
width: 100%;
height: 300px;
position: relative;
background-color: #ebf;
}
.container .target {
position: absolute;
left: 50%;
top: 50%;
height:100px;
width:200px;
margin-top: -50px;
margin-left: -100px;
background-color:rgba(255, 255, 255, 0.6);
}
</style>
3「絶対配置 + calc() 関数」での上下左右の中央寄せ
負のマージンの手法と似ていますが、こちらは、CSS「calc関数」を使った方法です。縦、横方向にそれぞれ半分をマイナスしてずらします。
<div class="container">
<div class="target">このブロックは中央に揃えました。</div>
</div>
<style>
.container {
width: 100%;
height: 300px;
position: relative;
background-color: #cef;
}
.container .target {
height: 100px;
width:200px;
position: absolute;
top: calc(50% - 50px);
left: calc(50% - 100px);
background-color:rgba(255, 255, 255, 0.6);
}
</style>
基本的にcalc() 関数を用いれば、いままで難しかったレイアウトの多くが容易に実現できるようになります。ただし、対象要素の縦幅、横幅大きさを固定してやる必要があります。なお、calc() 関数は、現在ではほとんどのモダンブラウザでサポートされています。これは便利ですね。
Internet Explorerだと9以降でないとサポートがないようですが、果たして、IE8のようなユーザを対象としたウェブサイトを作ろうとしているのかどうか・・・というところは考えてみてもよいでしょう。
calc() 関数は便利だけど、使いすぎるとCSSが複雑になって、メンテナンスしにくくなりそうだね。注意して使おう。
4「絶対配置 + transform」での上下左右の中央寄せ
「transform:translate()」によって、対象要素の表示をずらす事ができます。その要素の縦・横それぞれ50%ずらす、という指定が可能ですので、この特性をうまく利用します。transformで入力する%値は、要素自身の幅と高さを基準に相対的に計算されますので、「自分の50%」といった表現が容易に可能です。
<div class="container">
<div class="target">このブロックは中央に揃えました。</div>
</div>
<style>
.container {
width: 100%;
height: 300px;
background-color: #fca;
position: relative;
}
.container .target {
width:200px;
height:100px;
margin: auto;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color:rgba(255, 255, 255, 0.6);
}
</style>
CSSは非常にすっきり記述できます。ただし、transform プロパティは、IE10以降のサポートとなります。同様にIEのサポートに関してはそもそもサポートするかどうかが判断基準ですが・・・、これよりは前述のcalc関数の方が、サポート範囲が広いでしょうか。
5「 flexbox 」を利用した上下左右の中央寄せ
こちらはグリッドレイアウトで重宝するFlexboxを利用した方法です。本来は、複数の要素をグリッド状に並べるためのものですが、1つだけの要素にも適応できます。対象要素の高さが、コンテンツにフィットするように自動計算できるのは便利な点です。
<div class="container">
<div class="target">このブロックは中央に揃えました。</div>
</div>
<style>
.container{
width:100%;
height:300px;
background-color:#efc;
display:flex;
}
.container .target{
flex:0 1 auto;
width:200px;
margin:auto;
background-color:rgba(255, 255, 255, 0.6);
}
</style>
FlexboxもIEでは、10以降のサポートとなります。
Flexboxのプロパティに関しては、こちらで網羅的に解説していますので、興味のある方はぜひご覧ください:
Flexbox は、IEのサポートがなかったので利用しにくかったけど、近年は利用が増えてきたみたいだね。
CSSによる画像要素の上下左右の中央寄せ
基本的には画像もimg要素であれば、displayプロパティでインラインか、ブロックかどちらかに設定し、上記で解説した2つの方法が適応できます。
ただし、画像の表示に関しては、要素の背景として設定する「background-image」を使った設定方法もありますので、改めてこのセクションにくくりだして網羅しておきます。
インラインのIMG要素の上下左右の中央寄せ
imgタグは、デフォルトではdisplay:inlineのインライン要素です。つまり、上述のline-height作戦でも、ある程度中央寄せが可能です。(正確には、imgタグは「replaced-element」と呼ばれる種類の要素で、配置と描画はブラウザ実装依存となります。多くブラウザでは、inline-blockのような振る舞いをします)
<div class="container">
<img class="target" src="https://www-creators.com/wp-content/uploads/2017/05/1.png">
</div>
<style>
.container {
width: 100%;
line-height: 300px;
text-align: center;
position: relative;
background-color: #fcd;
}
.container .target {
vertical-align:middle;
height:120px;
}
</style>
ただし、上述のように、line-heighと vertical-align:middle の組み合わせでは、ベースラインの高さの分だけずれるため、厳密に正確な「中央寄せ」とはなりません。特にこのような画像は明確な四角形ですので、微妙なズレが問題になることもあるでしょう。
正確な中央寄せを実現するために、ひと手間増えますが、imgタグをblock化し、あとは、ブロック要素を中央寄せするための一般的な方法を適応すればOKです。ブロック要素化したIMGの中央寄せは、下記に続きます。
ブロック化したIMG要素の上下左右の中央寄せ
IMGタグを使って画像をセンタリングする場合は、ブロック化する方法のほうが幾分おすすめです。IMG要素の縦・横のいずれか片方を「auto」のままにしておくと、画像要素のアクペクト比(縦横比)が崩れることはありません。
<div class="container">
<img class="target" src="https://www-creators.com/wp-content/uploads/2017/05/1.png">
</div>
<style>
.container {
height:300px;
background-color: #efc;
}
.container .target {
display:block;
position:absolute;
height:100px; /* widthの値はデフォルトがauto */
top:0;
bottom:0;
right:0;
left:0;
margin:auto;
}
</style>
画像要素は見た目が四角いから、ブロック化したほうが直感的に扱いやすいケースも多い気がするね。
背景画像(background-image)として表示する場合
画像を配置する時は(特別な強い理由がない限りは)IMGタグよりも、CSSの background-imageプロパティを利用するのが、レイアウトにおいては便利です。「background-repeat: none」を追記して、背景画像の繰り返しを抑制している点に注意して下さい。
<div class="container"></div>
<style>
.container{
display:block;
height:300px;
background-image: url(https://www-creators.com/wp-content/uploads/2017/05/1.png);
background-position: center;
background-size:150px;
background-repeat: no-repeat;
background-color:#fec;
}
</style>
このようなケースで特に使用頻度が高いのは、background-size の設定値、「cover」「contain」です。これらのキーワドのいずれかで、画像の自動サイズ調整を行うことができます。
background-size の設定値
設定値 | 解説 |
---|---|
cover | 要素に空白ができないように拡大します。はみ出した部分を切り落とします。 |
contain | 縦、横のいずれかで、要素の長さを満たすように拡大します。(要素をはみ出しません) |
「background-size」と、「background-position: center」を組み合わせれば、画像の中央配置で必要となる配置方法のほとんどは実現できるでしょう。
<div class="container"></div>
<style>
.container{
display:block;
height:300px;
background-image:url(https://www-creators.com/wp-content/uploads/2017/05/1.png);
background-position:center center;
background-size:contain;
background-repeat:no-repeat;
background-color:#fef;
}
</style>
一方で、このbackgroundプロパティを使うと、img タグのaltのような値を設定できないため、SEO観点で不利だと言われています。ですが、もしそのページが十分にテキストを配置できる限りは、画像の近くに十分なテキストを配置することで、十分カバーできこともあるはずです。alt 値は、そのページの価値の全てを左右するような魔法のキーワードではないからです。
ALT属性を利用しなければならないなど、SEO上の強い理由がない限りは、background として中央寄せしたほうが、シンプルに記述できるね。
【補足】HTMLとCSSの基礎知識:インラインとブロック
インラインレベル、ブロックレベルとは?
CSSでの中央寄せ配置を考える際に、その要素の「display」プロパティがどのように指定されているのか、意識する必要があります。displayプロパティが取りうる値は複数ありますが、その値によって要素は下記の2つに大きく分類されます。
- インライン(inline)レベルの要素
- ブロック(block)レベルの要素
これらは、その要素や、その要素が内包するテキストがどのように描画されるかを左右します。これらの概念は、CSSLevel 2 Containing Block で定義され、その後、CSS Display Module Level 3 ではCSS2の定義を置き換えるように再定義されています。
詳細な概念の理解を追求すれば逆に混乱しやすいですので、開発者は「どちらの値であれば、どのように描画されるか」にフォーカスして理解したほうが良さそうです。CSS仕様はバージョンが上がっても後方互換を保つように設計されていますので、ここでは理解しやすさのため、CSS Level 2 にもとづいて解説します。
HTMLでの配置における違い
それぞれのHTML要素(=タグ)の種類には、CSSプロパティのdisplay値の初期値として、inline、block、table、inline-block, …, など、なんらかの値が割り振られています。例えば、img要素、a要素、span要素は「inline」がデフォルトです。また、div要素、p要素は「block」がデフォルト値です。また「display: table」と指定された要素も、その描画において「ブロックレベルの要素」として扱われます。
しかしながら、デフォルトでインライン要素であっても、CSSの「display」プロパティを使って、「display:block」を指定すればブロックレベルに、「display:inline」を指定すれば、インラインレベルとして扱う事ができます。
displayの値と要素の種類(CSS2)
要素 | displayの値 |
---|---|
ブロックレベル | block, list-item, table, inline-table, table-xxx(種々のtable内の値(省略)) |
インラインレベル | inline, inline-table, inline-block |
必要に応じて、これらのデフォルト値を上書きするように、CSSからdisplay 値を設定する事もあるでしょう。こちら、インラインとブロックの描画の違いをイメージで表したものです。
インラインはテキストの文字が(左寄せであれば)左側に、行内に次々に流れ込むように表示されます。一方で、ブロックは見た目的に「あたかもブロックように」描画されます。また、ブロックレベルの要素に内包された、タグで囲まれていないテキストはすべて、インライン要素として振る舞います。
中央寄せの概念
上記の概念を踏まえると、例えば、インラインレベルのテキスト要素に対して「text-align: center」が意味を持たないことが分かります。「text-align」は、「そのブロック要素が内包するインライン要素の上下方向の配置方法」指定ですので、インライン要素自体にこの設定値は無効です。また別の例では、「width」プロパティは、ブロックレベル要素には有効ですが、インラインには意味を持ちません。
このように、要素がインラインとブロックかを理解する事は、CSSでの中央寄せを正しく理解するためは、必要不可欠といえるでしょう。
HTMLとCSSでの、中央寄せの参考情報
CSSプロパティ「vertical-align」の詳細です。インラインの中央寄せにおいては、重要なプロパティです。
お疲れ様。中央寄せはいろいろ方法があるので、状況にあわせて使いこなせるようになりたいね。
text-align:center; は、div, p, h1 などのブロックレベルの要素に対して適応するんだね。