高さを揃えるレイアウトの解決策
フロントエンドのページ制作において、要素の高さを揃えるレイアウトに遭遇することはよくある。最も直感的な方法は、コンテナ内のすべての要素を float や inline-block に設定することだ。
float と inline-block
float でレイアウトを組む場合、親要素のコンテナを押し広げる(clearfix)必要があるだけでなく、子要素に対しても margin を設定しなければならない。 そのため、コンテンツが多すぎたり、高さが足りなかったりすると、すぐにレイアウト崩れが起きてしまう。
さらに、このようなレイアウトの最大の欠点は、高さを設定しなければならないことだ。
では、高さを設定しなければどうなるか?
たとえ min-height を設定したとしても同じで、コンテンツが高さを超えてしまった場合、必ず overflow の危機に直面することになる。
その後、CSS の media query を使って画面幅ごとに異なる高さを指定することにした。 この解決策は面倒だし、少し不格好ではあるが、画面幅が狭くなったときにレイアウトが崩れる問題は確かに解決できた。
この問題はずっと僕の心の奥底にくすぶっていたが、最近になって flex の奥深さに気づいた。
レイアウトに困ったら、まずは flex を考えてみる
人生で挫折したときは、flex のことを思い出そう。このフレキシブルボックスは、しばしば僕たちを救ってくれる。 flex はすでに主要なブラウザのほとんどでサポートされており、本当に使い勝手がいい!
display を flex に設定した際、子要素に高さを指定していなければ、子要素の高さはその中で最も高いものに揃えられる。
たった1行のプロパティで、僕がずっと悩んでいた問題を解決してくれた。実にエレガントな flex だ。
しかしそれだけでなく、レイアウトに少し調整を加える必要がある。flex はデフォルトで flex-wrap プロパティが設定されていない場合、1行で表示しようとして親コンテナを突き破ってしまう。
そのため、もう1行追加することができる。
.wrap {
flex-wrap: wrap;
}
これで、height を宣言することなく、高さを揃えたレスポンシブレイアウトの完成だ。おおよその CSS はこんな感じになる:
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.card {
height: auto;
width: 30%;
border: 1px solid #aaa;
}
flex をサポートしていないブラウザはどうする?
まず大前提として、flex はすでに大半の主要ブラウザでサポートされている。「対応状況」を言い訳にして、こんなにも便利な flex を敬遠するべきではない。
それでもブラウザが本当にサポートしていない場合は、JavaScript でレイアウトを組む方法がある。基本的な原理は高さを設定せず、container 内の全要素を検知して最も高い要素を見つけ出し、その高さを各要素に適用するというものだ。
ごく基本的なサンプルコードを書いてみた:
var cards = document.querySelectorAll(".card")
function getMaxinumHeight(elements) {
var nums = []
elements.forEach(function(value) {
nums.push(value.offsetHeight)
})
return nums.sort(function(a, b) {
return a < b
})[0]
}
var maxHeight = getMaxinumHeight(cards)
cards.forEach(value => {
value.style.height = maxHeight + "px"
})
Table is new sexy
古めかしい table レイアウトは今や敬遠されがちだが、等高レイアウトのような場面で、不運にも flex が使えない場合は table の特性を利用して高さを揃えることができる。
table レイアウトを実装するには、display: table、display: table-row、display: table-cell を使えばよい。
display: table は <table> に相当し、display: table-row は <tr>、display: table-cell は <td> に相当する。
だが、等高の効果は得られるものの、HTML のマークアップはより複雑になってしまう。さらに table の利用には制約もあり、例えば table の内部では margin が効かないなど、モックアップを実装する上で大きな障害となる。だから、flex が使える状況であれば、できるだけ flex を使うのがおすすめだ!
関連記事
関連記事
- Three.js で僕の部屋を表現する 僕が React Three Fiber を使って実際の自分の部屋をブラウザ上に再現し、実世界のオブジェクトを目録に見立て、空間の記憶を通してここ数年の生活と仕事について語った話。
- フロントエンドで画像を扱う際に注意すべきこと Jake Archibaldの記事を起点に、現代のレスポンシブ画像の書き方を整理する。なぜwidth/heightを付ける必要があるのか、CSSのaspect-ratioはいつ使うべきか、AVIFとWebPの選び方、そしてpicture/source/srcsetを使ったモバイル向け画像の切り替えについて。
- CSS field-sizing — たった1行のCSSでフォーム要素を自動リサイズする かつてtextareaの自動高さ調整は、JavaScriptでscrollHeightを監視するしかなかった。しかしCSSのfield-sizing: contentなら、わずか1行で代替でき、textarea、input、selectに対応している。本記事では従来のやり方のペインポイントと、field-sizingの使い方をまとめる。
- リンクの下線をもっと見栄え良くする:text-underline-offset デフォルトでは下線と文字が近すぎて、このスタイルを好まないデザイナーもいるし、僕自身もあまり綺麗ではないと感じていた。