【Flexbox】孫要素まで高さを揃える方法と、うまく行かない時の対処法(追記あり)
Wordpress等で記事の一覧をFlexboxで横並びにすることはよくあると思います。
デザインカンプなどでは「良い感じ」の文字量で作られていることが多いので気にならなくとも、実際に運用が始まった後に「記事毎にタイトルの長さが違っているので高さが揃わず気持ち悪い」ということはよくあると思います。
自分でも良く忘れるのでので、備忘録も兼ねて。
完成形
まず、目指すべき完成形はこんな感じです。
分かりやすいようにタイトル部分に背景色を付けましたが、タイトル部分の高さが揃っているのでボタンの位置もそろっており、細かいことを言ってくるクライアントやディレクターも満足してくれるでしょう。
このタイトル部分の高さが記事によって異なることで良く陥りがちなレイアウト崩れがこちら。
タイトル行くらいであれば1行~2行で収まるのでそこまで気にならないかもしれませんが、例えば商品説明などが入る場合は参考画像の比じゃないくらいテキスト量の違いが出てしまう可能性があるので、後々致命的になり得ます。
この時のコードを抜粋して記載。
※CSSもHTML内に書いちゃってます。リセットは割愛します。
<html>
<head></head>
<body>
<style type="text/css">
.wrapper {
width: 1024px;
margin: 0 auto;
padding: 60px 20px;
background-color: #ddd;
}
.archive-list {
display: flex;
}
.archive-item {
width: 30%;
padding: 10px;
background-color: #fff;
}
.archive-img-wrap {
width: 100%;
height: 150px;
margin-bottom: 10px;
}
.archive-img-wrap img {
width: 100%;
height: 100%;
object-fit: cover;
}
.archive-item:not(:nth-child(3n)) {
margin-right: 20px;
}
.archive-ttl {
margin-bottom: 10px;
line-height: 1.5;
background-color: skyblue;
}
.btn-more {
display: block;
margin: 0 auto;
height: 40px;
line-height: 40px;
border-radius: 20px;
padding: 0 20px;
text-align: center;
background-color: navy;
color: #fff;
}
</style>
<div class="wrapper">
<ul class="archive-list">
<li class="archive-item">
<div class="archive-img-wrap">
<img src="./thum.png" alt="">
</div>
<p class="archive-ttl">タイトルタイトルタイトルタイトル</p>
<a href="" class="btn-more">詳しくはこちら</a>
</li>
<li class="archive-item">
<div class="archive-img-wrap">
<img src="./thum.png" alt="">
</div>
<p class="archive-ttl">タイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトル</p>
<a href="" class="btn-more">詳しくはこちら</a>
</li>
<li class="archive-item">
<div class="archive-img-wrap">
<img src="./thum.png" alt="">
</div>
<p class="archive-ttl">タイトルタイトルタイトルタイトルタイトルタイトルタイトル</p>
<a href="" class="btn-more">詳しくはこちら</a>
</li>
</ul>
</div>
</body>
</html>
適当に書いたのでツッコミどころがあるかもしれませんが、よくある形だと思います。
このコードに3行付け足すだけで解決しますので順を追ってみていきます。
子要素をdisplay:flexして縦並びにする
.archive-item {
width: 30%;
padding: 10px;
background-color: #fff;
display: flex;
flex-direction: column;
}
display: flex;
flex-direction: column;
を追加しました。
まだ見た目は変わっていません。
孫要素にflex-glowを設定する
.archive-ttl {
margin-bottom: 10px;
line-height: 1.5;
background-color: skyblue;
flex-grow: 1;
}
flex-grow: 1;
を追加しました。
これで完成形の見た目になっています。
(読み飛ばし可)簡単な説明
まず、display:flexすると、align-itemsの初期値は「normal」です。
Flexboxにおける「align-items: normal」は「align-items: strech」とイコールです。横並びになった子要素の高さが揃うように高さが伸びます。
次に、孫要素の「タイトル」部分だけ自由に伸び縮みするようにしたいので、孫要素に「flex-glow:1」を付けたいわけですが、子要素がFlexboxになっていないと意味をなさないので、子要素をFlexboxにしているという訳です。
敢えて説明するまでも無いですが、子要素に「flex-direction」を設定しないと孫要素も横並びに配置されてしまうので、「flex-direction: column」を設定しているわけです。
うまく行かない時に見直すポイント
1.親要素にalign-itemsを設定していないか
.archive-list {
display: flex;
align-items: flex-start;
}
このように親要素にalign-itemsを設定してしまうと、初期値の「align-items: normal(strech)」が上書きされてしまうので、子要素の高さが揃わなくなってしまいます。
私がflexを書く時はmixinを使ったりコピペしたり、必要もないのにalign-itemsを設定してしまっていることがあるので、稀に良くやってしまうミスです。
2.子要素にheightを指定していないか
.archive-item {
width: 30%;
padding: 10px;
background-color: #fff;
display: flex;
flex-direction: column;
height: 100%;
}
これもうっかり脳死的にやってしまうのですが、子要素にheightをしていしまうと「1.」と同様に子要素の高さが揃わなくなってしまいます。
※私は今日これで1時間ハマりました
お決まりの文句
いかがでしたでしょうか?
今回説明した方法以外にも、px指定を駆使する、matchheightで対応する等の方法があると思いますが、「今現役のブラウザほぼ全て網羅できる」「JSを使わなくて良い」という理由でスマートな方法かなと思います。
display:gridを使えば悩まなくても良い気もしますが、IE11のサポートが「完全に」なくるなるまでは2029年を待つ必要がありますので、しばらくこの方法で凌ぐ必要がありそうです。
追記
本記事の書き方だと、ボックス全体をクリッカブルにしたいという代理店が良く言ってきそうな要望に対応できないので、別記事を追加しました。
誰かの参考に慣れば嬉しいです。