高度相同的排版解決方案

在前端的頁面中,我們經常會碰到需要相同高度的排版。最直覺的方法就是將容器裡的所有元素設為 float 或是 inline-block。

float 及 inline-block

如果是使用 float 排版,不但要先撐開父元素容器(clearfix),還要針對子元素設定 margin。
所以一旦內容太多,或是高度不足就會跑版。

而且,這樣的排版最大的缺陷就是,必須設定高度

那,如果不設置高度呢?
就算設定了 min-height 也一樣,當內容超出高度時,就必定會面臨 overflow 的危機。

example1

後來決定直接用 css media query 在不同的螢幕寬度下分別給予不同的高度。
雖然解法比較麻煩,也比較醜一點,但的確解決了寬度過窄時會跑版的問題。

這個問題後來一直深埋在心中,直到最近發現了 flex 的奧秘。

排版遇到困難,先想想 flex

人生遇到挫折的時候,想想 flex,這個彈性盒子常常會救你一命。
flex 已經支援大部分的主流瀏覽器,而且真的很好用!

將 display 設置為 flex 的時候,如果子元素沒有設定高度,則子元素的高度會是其中最高的那個。

一行屬性就解決了我朝思暮想的問題,真是優雅的 flex

但除此之外,我們還需要對排版做一些調整。 flex 預設如果沒有設置 flex-wrap 屬性的話,就會以單行顯示的方式來撐開父容器。
因此我們可以再加上一行。

1
.wrap { flex-wrap: wrap; }

好了,高度相同的 responsive 排版,不宣告 height 就此完成。大概的 css 會長得像這樣:

1
2
3
4
5
6
7
8
9
10
11
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.card {
height: auto;
width: 30%;
border: 1px solid #aaa;
}

不支援 flex 的瀏覽器怎麼辦?

首先 flex 已經支援大部分的主流瀏覽器了,不要用支援度這種藉口來忽視這麼好用的 flex
但如果瀏覽器真的不支援,可以用 js 的方式來做排版。主要的原理是不設定高度,偵測 container 裡面的所有元素,並且找出高度最高的,並將此高度套用到每個元素中。

寫了一個很基本的範例代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 的 markup 變得更複雜了。而且 table 在使用上仍然有一些限制,像是 margin 沒辦法在 table 裡頭生效等等,這些在實作 mockup 時都是很大的阻礙。所以,如果能夠用 flex 來做的話,就盡量使用 flex 吧!

延伸閱讀

Flexbox responsive equal height

分享到