この記事は、アソビュー! Advent Calendar 2022 の 17日目(裏面)です。
みなさん、こんにちは。アソビュー!でフロントエンドエンジニアをしている白井です。
弊社ではバックエンドエンジニアの比率が多いこともあり、CSS 怖い!CSS わからない!という声をよく聞きます。
CSS と少しでも仲良くなるために、今回はレイアウトを作る際に基本となる幅(width
)、高さ(height
)、余白(margin
)を指定する際に考えていることなどお話ししようと思います。
まずはじめに
レイアウトを整える前に、不要な CSS プロパティは消しておく
普段作業していて CSS を書き換えていると不必要なスタイル定義は意外と残ってしまいがちです(よくやってしまいます…)。
色や形に関するプロパティは大体決まっているので重複したりすることは少ないですが、要素の位置は display
、position
、margin
、width
、height
…など、様々なプロパティの組み合わせによって決定されるため、余計なものはなるべく削除しておいた方が見通しが良くなります。
たとえば、
- 要素のデフォルトスタイルを適用している
- 既に適用済みのスタイルを再適用している(よくある)
- オーバーライドしているが、優先度の関係で適用されていない
これらはコード上で分かるものは削除し、わからない場合は Chrome DevTool などで確認して削除・修正しています。
例
<div class="list"> <span class="item">...</span> </div> <style> .list { margin: 0; // ① width: 100%; // ② } .list .item { color: yellow; // ③ } .item { display: inline; // ④ color: cyan !important; } </style>
- ① 実は全ページで読み込んでいる reset CSS で
margin: 0
を適用済み - ②
div
はブロック要素のため、もともとwidth
は100%
- ③
color
をオーバーライドしているが、優先度で負けているため適用されない - ④
span
はインライン要素のため、もともとdisplay
はinline
適用する要素のタグが不特定(block
にも inline
にもなる可能性がある)場合に display
を固定化する意味で設定したり、flex-item
要素になったときには width: 100%
ではなくなるためあえて 100%
の指定が必要など、シーンに応じて必要・不必要は考えなくてはならないですが…
width の指定
昨今ではレスポンシブ対応をすることがほとんどだと思うので、常に画面幅が増減したときのことを考える必要があります。
width → max-width に変える
width
の指定をすると、画面幅が縮んだときにコンテンツが収まりきらなくなる可能性が出てくるので、幅が変化する方が困るという時以外はなるべく指定しないようにしています。
代わりに、max-width
を使って最大幅だけ決めておき、その幅以下になった場合に可変するようにしておく(width
は 100%
になっていること前提)と画面幅が縮んだときのことを考えなくて済みます。
例:800px のコンテナの幅指定
PC では 800px
、それ以下では親要素に依存した 100%
になっているような想定です。こういったコンテナは max-width
にしておくだけでレスポンシブに対応が楽になります。
.container { max-width: 800px; margin-right: auto; margin-left: auto; }
子要素の width は grid-template を使う
要素を横並びして、均等の幅で子要素を並べるようなシーンで width
を指定することはよくあると思いますが、親の幅、子要素の数、余白の値からどれくらいの値を設定するか計算する必要があります。
そこで、子要素に width
は持たせず、親要素を grid
にして子要素の幅を grid-template
で設定することで width
を自動計算させることができます。
例:子要素を3列、均等幅で配置にするときの指定
親要素を grid
にして列幅を指定、さらに均等幅で配置する場合は要素の数で自動計算してくれる 1fr
の単位を使います。これでよりフレキシブルになります。
<section class="cards"> <div class="card"> <div class="card"> <div class="card"> </section> <style> .cards { display: grid; grid-template: auto / repeat(3, 1fr); max-width: 800px; margin: 0 auto; gap: 10px; } .card { ... } </style>
grid-template
は 行の高さ・数 / 列の幅・数
の設定を行えます。ここでは、
- 行:1行、高さは
auto
のため中身によって可変します。 - 列:3列(
repeat(3, 1fr)
は1fr 1fr 1fr
の意)、長さは全て1fr
で3列の要素が均等の幅で配置されます。
例2:子要素を3列、列幅を指定して段落ちできるようにする
幅の指定が必要になりますが、auto-fit
と組み合わせると flex
要素のように収まりきらない要素を段落ちさせることもできます。
ここでは minmax()
を使い min
の値を auto
とすることで、親要素が 200px
を下回ったときに親要素に合わせて縮小させることができます。
.cards { display: grid; grid-template: auto / repeat(auto-fit, minmax(auto, 200px)); justify-content: center; margin: 0 auto; gap: 10px; }
height の指定
height
は画像の大きさ、テキスト量などによって変化することが多いため、height
で高さを固定化してしまうと、はみ出たり崩れてしまう可能性があります。動的ではなく静的コンテンツでも、レスポンシブで画面幅が増減した時にテキストの改行によって高さが変化した時のことを考えなくてはなりません。
padding を使う
height
はその名の通り高さを設定するプロパティですが「見た目を整えるためにとりあえず高さがほしい」という理由では設定せず、高さが欲しい場合はまず padding
で調整するようにしています。
コンテンツに応じて高さも増えるのではみ出したりすることなく、またほどよい余白をあけるという意図もあります。
min-height を使う
height
を使いたくなった場合、最小の高さを保持してそれ以上になったときに可変してくれる min-height
で整えると変化に強くなります。
基本的には height
は設定せずに高さは中身のコンテンツに任せて padding
で調整、それでも高さの設定が必要な場合に min-height
、それでも難しい場合は height
を設定する くらいの気持ちで考えるようにしています。
例:ボタンコンポーネント
height
を使わずに padding
と min-height
で高さ調整した例です。
(ここまでウィンドウが縮まることは無いと思いますが、2列で配置された時などを想定)
.button { display: flex; align-items: center; justify-content: center; min-height: 30px; padding: 10px; background-color: cadetblue; color: white; box-sizing: border-box; }
padding
の設定- 高さを調整する前にまず
padding
を入れます。font-size
が変化するような場合、em
の単位を使うと文字サイズに対応した余白をあけることができます。
- 高さを調整する前にまず
min-height
の設定padding
の調整である程度の高さは取られているはずですが、中途半端な値になったり、最小の高さをもっと取っておきたいことも。デザイン上、きっちりした高さを設定したい場合はpadding
で調整しつつも「最低この高さは取りたい」というのをmin-height
で調整します。
padding
で高さの調整を行い、height
ではなく min-height
とすることで、ボタンの中の文字が二行になった場合でもデザインを保つことができます。
margin の指定
margin
は要素のコンテナの外側の余白を取るときに使用するプロパティです。
余白を取るために使うのは正しいのですが、margin
で余白を取っていくと、どの要素によって余白がとられているのかが分かりにくくなったり、margin
の相殺などを考えて各要素に設定されているプロパティをみて余白の計算を行う必要がでてきます。
要素間の余白は margin → gap に変える
要素間の余白を取る際、margin
の代わりに、親要素に display: flex
や display: grid
を設定し、子要素間の余白を一括設定できる gap
プロパティを使うと、親要素側で余白をコントロールできるようになり、管理しやすくなります。
例:各要素間に 10px ずつ余白をあける
<section class="list"> <div>...<div> <div>...<div> <div>...<div> </section> <style> .list { ... display: flex; flex-direction: column; gap: 10px; } </style>
これにより、子要素の記述量が減るため場合によってはクラスを付与する必要がなくなるというメリットもあります。
注意点として、iOS の flex
の gap
プロパティは 2021年4月の safari 14.1 から対応したため、バージョンの利用率などを見ながら使うかどうか判断するのがよさそうです。
一方で grid
の gap
は iOS は 2018年ごろ から対応しています。
ページは要素と要素の積み重ねで出来上がっていくので、その余白を gap
で取るようにすると margin
の出番はそこまで多くありません。
まとめ
よく使われる width
、height
、margin
プロパティですが、意外と使うシーンは少なかったりします。もちろん、組み方は色々あるので今回紹介した内容以外にも方法はありますが、なるべく記述量を減らし崩れにくいスタイリングをしていきたいですね。
レイアウトのプロパティといえば、他に display
や position
も外せないところですが、話が長くなりそうなのでまた別の機会に。
CSS プロパティも新しいものが増えてどんどん便利になっていくので、対応ブラウザ・シェア率と相談しながら徐々に使っていきましょう!
アソビュー!では一緒にはたらくメンバーを募集しています。 ご興味のある方いらっしゃいましたら、ぜひ一度お話ししましょう!