CSS Flexbox 佔滿剩餘高度時 Overflow 捲軸失效問題
0 |
今天處理到一個網頁需求,排版需求為上方區塊大小固定,剩餘高度擺入超長清單,清單要可垂直捲動。這類情境,自然要優先考慮用佔滿剩餘網頁寬/高度的美妙解法 - CSS Flexbox搞定,做法如下:
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
height: 100%; margin: 0; padding: 0; font-size: 10pt;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.main {
height: 100%; display: flex; flex-direction: column;
}
.banner {
flex-basis: 40px;
flex-shrink: 0;
background-color: #bbb;
}
.content {
flex-grow: 1;
background-color: #eee;
overflow-y: auto; border: 1px solid gray;
}
.long {
height: 2000px; background-color: #fff;
}
span { font-size: 9pt; color: #777; }
</style>
</head>
<body>
<div class="main">
<div class="banner">
Banner <span>height: 40px</span>
</div>
<div class="content">
Content <span>flow-grow: 1; overflow-y: auto;</span>
<div class="long">
Long Content <span>height: 2000px</span>
</div>
</div>
</body>
</html>
.main 容器設 display: flex,垂直排列 flex-direction: column;.banner 設固定高度 flex-basis: 40px (或 height: 40px,效果相同) 並指定 flex-shrink: 0 避免高度不足時被壓縮;最下方的 .content 則設 flex-grow: 1 佔滿剩餘高度,並指定 overflow-y: auto 當內容超出 .content 高度時顯示垂直捲軸;接著在 .content 放入高度為 2000px 的超長 DIV,規格達成:
然而,實際排版還有些額外要求,.main 要先分成 .top (固定高度 40px) 及 .container (吃滿剩餘頁面高度),.banner 及 .content 則搬進 .container 內,.container 的高度扣除 .banner 固定高度 40px,餘下都留給 .content 顯示可垂直捲動的超長清單。(註:真實案例比這個更複雜些,因為有水平方向的排版要求,無法簡化將 .top 40px、.banner 40px、.content flex-grow: 1 放在同一層縮放,只能寫成巢狀,這個範例為可重現問題的簡化版本)
感覺不難,該 .main 包 .container 做出兩層 display: flex; flex-direction: column 應該就可以了:
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
height: 100%; margin: 0; padding: 0; font-size: 10pt;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.main {
height: 100%; display: flex; flex-direction: column;
}
.top {
height: 40px; flex-shrink: 0; background-color: #aaa;
}
.container {
flex-grow: 1; display: flex; flex-direction: column;
}
.banner {
flex-basis: 40px; flex-shrink: 0; background-color: #bbb;
}
.content {
flex-grow: 1; background-color: #eee;
overflow-y: auto; border: 1px solid gray;
}
.long {
height: 2000px; background-color: #fff;
}
span { font-size: 9pt; color: #777; }
</style>
</head>
<body>
<div class="main">
<div class="top">
→ Top <span>height: 40px</span> <br />
↓ Container <span>flow-grow: 1</span>
</div>
<div class="container">
<div class="banner">
Banner <span>height: 40px</span>
</div>
<div class="content">
Content <span>flow-grow: 1; overflow-y: auto;</span>
<div class="long">
Long Content <span>height: 2000px</span>
</div>
</div>
</div>
</div>
</body>
</html>
事與願違,.content 被 .long 撐開高度,整個頁面跟著拉長,有看到垂直捲軸,卻是整個網頁一起捲。
經過一番研究,學到神奇解法,在 .content 的 CSS 樣式加入 height: 0;: (註:建議改用文末補充之 min-height 解法)
.content {
flex-grow: 1; background-color: #eee;
overflow-y: auto; border: 1px solid gray;
height: 0;
}
問題就這麼解決了!
關於這個解法的原理,似乎可以歸因到 CSS Flexbox 規格:4.5. Automatic Minimum Size of Flex Items,不少討論提到可藉由設定 min-height: 0 解決,但我實測的結果設定 height: 0 才有效,網路上也有些類似回報:1、2,推測可能與 Edge/Chrome 瀏覽器實作有關。
【2023-06-27 更新】發現更好的解法,改在上一層 .container 加入 min-height: 0,效果相同,且語意上不易混淆。
.container {
flex-grow: 1; display: flex; flex-direction: column;
min-height: 0;
}
Overflow issues in CSS flexbox layout.
Comments
Be the first to post a comment