在前端的頁面中,我們經常會碰到需要相同高度的排版。最直覺的方法就是將容器裡的所有元素設為 float 或是 inline-block。
float 及 inline-block
如果是使用 float 排版,不但要先撐開父元素容器(clearfix),還要針對子元素設定 margin。 所以一旦內容太多,或是高度不足就會跑版。
而且,這樣的排版最大的缺陷就是,必須設定高度。
那,如果不設置高度呢? 就算設定了 min-height 也一樣,當內容超出高度時,就必定會面臨 overflow 的危機。
後來決定直接用 css media query 在不同的螢幕寬度下分別給予不同的高度。 雖然解法比較麻煩,也比較醜一點,但的確解決了寬度過窄時會跑版的問題。
這個問題後來一直深埋在心中,直到最近發現了 flex 的奧秘。
排版遇到困難,先想想 flex
人生遇到挫折的時候,想想 flex,這個彈性盒子常常會救你一命。 flex 已經支援大部分的主流瀏覽器,而且真的很好用!
將 display 設置為 flex 的時候,如果子元素沒有設定高度,則子元素的高度會是其中最高的那個。
一行屬性就解決了我朝思暮想的問題,真是優雅的 flex
。
但除此之外,我們還需要對排版做一些調整。 flex 預設如果沒有設置 flex-wrap
屬性的話,就會以單行顯示的方式來撐開父容器。
因此我們可以再加上一行。
.wrap {
flex-wrap: wrap;
}
好了,高度相同的 responsive 排版,不宣告 height
就此完成。大概的 css 會長得像這樣:
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.card {
height: auto;
width: 30%;
border: 1px solid #aaa;
}
不支援 flex 的瀏覽器怎麼辦?
首先 flex 已經支援大部分的主流瀏覽器了,不要用支援度這種藉口來忽視這麼好用的 flex
。
但如果瀏覽器真的不支援,可以用 js 的方式來做排版。主要的原理是不設定高度,偵測 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 的 markup 變得更複雜了。而且 table 在使用上仍然有一些限制,像是 margin 沒辦法在 table
裡頭生效等等,這些在實作 mockup 時都是很大的阻礙。所以,如果能夠用 flex 來做的話,就盡量使用 flex 吧!