【CSS】1行のテキストを両端揃えする方法
1行のテキストを両端揃えしたいことってありますよね。たとえば以下のようなデザインに出会ったことはないでしょうか。
「うどん」「そば」「ラーメン」のテキストが両端揃えになっています。
今回はこのようなデザインをCSS(もしくはHTMLとJavaScript)で実現する方法について考えてみます。
text-align-lastを使う
CSSのtext-align-last
プロパティが使える環境あれば話は簡単です。
肝となるのは以下の箇所ですね。text-align-last:justify
を設定することで、テキストが両端揃えになりました。
dt {
text-align-last: justify;
}
上記はベストな解決策に思えます(実際モダンブラウザの最新バージョンを対象にしているならベストだと思います)。しかし、16.0以前のSafariではサポートされていないという懸念点があります。
では、それ以前のブラウザをサポートするためにはどうしたら良いのでしょうか。本記事ではいくつかの実装方法を考えていきます。
スペースを入力する
もっともシンプルな方法はスペースを入れることでしょう。
等幅フォントであれば、スペースを入力することで解決できることがあります(文字数によってはできないこともある)。
ただし、上記を見てもわかるように「うどん」と「そば」では問題ありませんが、「うどん」と「ラーメン」では文字数の関係でバランスが悪くなってしまいます。
letter-spacingを使う
letter-spacing
を使って文字間を調節してみましょう。
下記の実装例では等幅フォントで文字間の調節を行なっていますが、等幅ではないフォントを使用している場合は調整が難しいかもしれません(実際に目で見て調節する必要がある)。
letter-spacing
は最後の文字の後ろ側にもスペースができてしまうので、マイナスマージンで相殺します。
dt[data-num="3"] {
/* 相殺マージン */
margin-right: -0.5em;
letter-spacing: 0.5em;
}
この方法では文字数によってletter-spacing
の値が左右されるので、管理コストが大きくなるかもしれません。また、フォントによっては文字間の調節が非常に難しくなる可能性もあります。
等幅フォントであれば、次のようにCSS変数とcalc
を使って管理することが可能です。
dt {
/*
--result = (最大の文字数 - 対象の文字数) / (文字間の数)
今回の最大の文字数は「ラーメン」なので4
*/
--result: calc((var(--max-num) - var(--num)) / (var(--num) - 1));
margin-right: calc(var(--result) * -1em);
letter-spacing: calc(var(--result) * 1em);
}
1文字ずつspanタグで囲む
スペースやletter-spacing
を使う方法は、管理コストの問題や使用できる場面が限定的で汎用性に欠ける問題がありました。したがって、実際にはspan
で囲う方法を採用することが多いかもしれません。
上記の実装例ではJavaScriptを使用してテキストをspan
で囲っていますが、HTML側でspan
を書いてもとりわけ問題はありません。
text-alignを使う
ここまでにいくつかの実装を書いてきましたが、本記事を書こうと思ったきっかけはこの方法になります。
justify
インラインコンテンツは両端揃えされます。テキストは最終行を除いて、その左右の端が行ボックスの左右の端に揃うように間隔が空けられます。
MDNに記載がある通りtext-align:justify
は最後の行に適用されません(つまり1行だと適用できない)。そもそもtext-align:justify
が1行のテキストに適用できるならtext-align-last
は必要ないじゃん、というのはごもっともな意見です。
ではどうするのかというと、1行ではなく強引に2行にすることでtext-align:justify
を適用します。
重要なのは下記の辺りです。
擬似要素をつかって、dt
を2行にしています。加えてgrid-auto-rows
で高さを指定しています。この時、line-height
の計算を忘れないようにしてください。
:root {
--line-height: 2;
}
dl {
display: grid;
grid-template-columns: auto 1fr;
/* 高さを指定。line-heightの考慮を忘れずに */
grid-auto-rows: calc(1em * var(--line-height));
line-height: var(--line-height);
}
dt {
text-align: justify;
}
/* 2行にするために擬似要素(::after)でinline-blockかつ横幅100%を指定 */
dt::after {
content: "";
display: inline-block;
width: 100%;
}
強引な方法ではありますが、1行のテキストにもtext-align:justify
を適用することができました。
ddが複数行の時
上記ではdd
のテキストが複数行になったときのことを考慮していませんでした。dd
が複数行でも対応できるコードを載せておきます。
grid-auto-rows
で高さを指定しまうと高さが固定されてしまい複数行に対応できなくなるので、grid-auto-rows
を削除しました。代わりにdt
の中にspan
を入れて、そのspan
に対して高さを指定しています。
具体的に変更を加えたのは下記の辺りになります。
<dt><span>うどん</span></dt>
dt > span {
display: inline-block;
width: 100%;
height: calc(1em * var(--line-height));
vertical-align: bottom;
overflow: hidden;
}
以上で隣りのdd
の高さを可変にしつつ、dt
は両端揃えにするということが実現できました。
おわりに
text-align-last
は非常に便利ですね。Safari以外ではそれなりのサポート率なので、text-align-last
を使用しつつ、Safari 16.0以前に関しては左寄せ(もしくは右寄せ)で表示するというのも1つの手だと思いました。
また本記事で紹介した方法は、自分で書いておきながら必ずしも良い方法とは言えなかったりもしますが、あくまで1つの手段として頭の片隅に入れておくと、どこかで使い道があるかもしれませんね。
他にも方法がありましたら、是非コメント欄より教えてください!
Discussion