Flexbox 的彈性伸縮
彈性盒子 Flexbox 除了基本的設定和對齊,也可以藉由作用於「彈性項目」的 flex、flex-grow、flex-shrink、flex-basis 樣式屬性,製造出可以根據不同的父元素寬度,進行「自由伸縮、彈性伸縮」的彈性項目,除此之外,也會透過彈性項目專用的 order 樣式屬性,改變彈性項目位置,這篇教學會介紹這些樣式屬性的用法。
快速導覽:
flex-grow 彈性項目擴展比例
flex-grow
樣式屬性會設定「彈性項目的擴展比例」,屬性值只支援「沒有單位、非負值的數值」,預設值為 0,可以使用浮點數,沒有繼承特性,使用後彈性項目會根據所設定的數值,自動分配彈性容器扣除未設定擴展比例的彈型項目內容空間的「剩餘空間」,計算公式如下 ( 寬度表示元素容器盒子的外邊界範圍 ):
下方範會使用兩組 div
,按照下列規則撰寫 CSS,可以看出第二組和第三組的第四個 div
,不論 flex-grow
數值為何,都會撐滿容器,而第一組只會保留自己的空間:
- 假設彈性容器寬度 400px。
- 內容有三個未設定擴展比例的彈性項目、一個設定
flex-grow:1
的彈性項目。- 假設三個未設定彈性項目的「內容與邊界」加起來共有 100px。
- 彈性容器寬度減去上述的 100px 還有 300px。
- 有設定
flex-grow:1
的彈性項目分配到 (300x1)/1,也就是「300px + 自己的容器空間」。- 有設定
flex-grow:4
的彈性項目分配到 (300x4)/4,也就是「300px + 自己的容器空間」。
<!-- HTML 程式碼-->
<div class="f g1"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<div class="f g2"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<div class="f g3"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px;
}
div div {padding: 5px 0px;}
div div:nth-child(1) {background: #f33;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
.g2 div:nth-child(4) {flex-grow: 1;} /* 第二組的第四個 div 設定彈性擴展 */
.g3 div:nth-child(4) {flex-grow: 4;} /* 第三組的第四個 div 設定彈性擴展 */
</style>
如果兩個以上的彈性項目設定了 flex-grow
,則同樣會按照計算公式計算彈性項目寬度,下方範例的第三個和第四個 div,會按照下方公式分配寬度 ( 假設剩餘空間為 300px ):
- 第三個 div (
flex-grow:1
):300 x 1 / ( 2 + 1 ) = 100- 第四個 div (
flex-grow:2
):300 x 2 / ( 2 + 1 ) = 200
<!-- HTML 程式碼-->
<div class="f g1"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px;
}
div div {padding: 5px 0px;}
div div:nth-child(1) {background: #f33;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
.g1 div:nth-child(3) {flex-grow: 1;} /* 第三個 div 設定彈性擴展 */
.g1 div:nth-child(4) {flex-grow: 2;} /* 第四個 div 設定彈性擴展 */
</style>
如果有「設定寬度」或「內容寬度較大」的彈性項目,則同樣會按照計算公式,先減去原本的寬度,再按照比例分配剩下的空間,下方的範例有三組 div,第一組原本的內容寬度都相,第二組的第四個 div 因為字元較多所以內容較寬,第三組的第三個 div 有設定寬度。
<!-- HTML 程式碼-->
<div class="f g1"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<div class="f g2"><div>o</div><div>o</div><div>o</div><div>oxxo</div></div>
<div class="f g3"><div>o</div><div>o</div><div>o</div><div>o</div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px;
}
div div {padding: 5px 0px;}
div div:nth-child(1) {background: #f33;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
.g1 div:nth-child(3) {flex-grow: 1;}
.g1 div:nth-child(4) {flex-grow: 2;}
.g2 div:nth-child(3) {flex-grow: 1;}
.g2 div:nth-child(4) {flex-grow: 2;}
.g3 div:nth-child(3) {
flex-grow: 1;
width: 100px;
}
.g3 div:nth-child(4) {flex-grow: 2;}
</style>
flex-shrink 彈性項目縮小比例
flex-grow
樣式屬性會設定「彈性項目的縮小比例」,屬性值只支援「沒有單位、非負值的數值」,預設值為 1,可以使用浮點數,沒有繼承特性,如果 flex-grow
樣式屬性是分配「剩餘的空間」,flex-shrink
樣式屬性就是分配「溢出彈型容器的空間」,計算公式如下 ( 寬度表示元素容器盒子的外邊界範圍 ):
<!-- HTML 程式碼-->
<div class="f g1"><div></div><div></div><div></div><div></div><div></div></div>
<div class="f g2"><div></div><div></div><div></div><div></div><div></div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {
padding: 5px 0px;
width: 100px;
}
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
.g1 div {flex-shrink: 0;}
.g2 div {flex-shrink: 1;}
</style>
<!-- HTML 程式碼-->
<div class="f g1"><div></div><div></div><div></div><div></div><div></div></div>
<div class="f g2"><div></div><div></div><div></div><div></div><div></div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {
padding: 5px 0px;
width: 100px;
}
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
.g1 div {flex-shrink: 0;}
.g2 div:nth-child(4) {flex-shrink: 6;}
</style>
<!-- HTML 程式碼-->
<div class="f g1"><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div></div>
<div class="f g2"><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div></div>
<div class="f g3"><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div><div>oxxo.studio</div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {padding: 5px 0px;} /* 彈性項目未設定寬度,讓內容自動撐開容器 */
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
.g1 div {flex-shrink: 0;}
.g2 div {flex-shrink: 1;}
.g3 div:nth-child(4) {flex-shrink: 6;}
</style>
flex-basis 彈性項目基礎比例
flex-basis
樣式屬性會設定「彈性項目的基礎比例」,屬性值只支援「具有單位且非負值的數值或關鍵字」,沒有繼承特性,下方列出可用的單位與關鍵字:
單位或關鍵字 | 說明 |
---|---|
px | 絕對長度單位。 |
% | 相對長度單位,數值為彈性容器寬度的百分比。 |
auto | 自動調整比例 ( 預設值 )。 |
0 | 所有彈性元素都設定為 0 時等於 auto。 |
content | 由內容決定寬度。 |
使用 flex-basis
時會有下列兩種情況,分別會產生不同的效果 ( 下方「寬度」表示預設的水平排列,如果改成垂直排列則是「高度」 ):
- 彈性容器空間 > 彈性項目總寬度:
flex-basis
屬性值為彈性項目寬度。- 彈性容器空間 < 彈性項目總寬度:根據
flex-basis
屬性值、本身長度、容器寬度換算實際寬度。
下方範例有四個轉換成彈性盒子的 div 群組,所有群組中第一個紅色 div 設定為 flex-basis: 50%;
,第二個橘黃色 div 設定為 flex-basis: 100px;
,第三第四的藍色綠色 div 設定為 flex-basis: 10px;
,最後一個紫色 div 設定為 width: 10px;
,執行後可以看到下列結果:
- 前兩組 div 是「彈性容器空間 > 彈性項目總寬度」,
flex-basis
的屬性值等於彈性項目的寬度。- 後兩個 div 是「彈性容器空間 < 彈性項目總寬度」,就會按照圖片說明的公式計算最後的結果。
flex-basis
對於彈性項目而言,設定數值後的效果與width
相同。
<!-- HTML 程式碼-->
<h3>彈性容器空間 > 彈性項目總寬度</h3>
<div class="f g1"><div></div><div></div><div></div><div></div><div></div></div>
<div class="f g2"><div></div><div></div><div></div><div></div><div></div></div>
<h3>彈性容器空間 < 彈性項目總寬度</h3>
<div class="f g3"><div></div><div></div><div></div><div></div><div></div></div>
<div class="f g4"><div></div><div></div><div></div><div></div><div></div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {padding: 5px 0px;}
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
div div:nth-child(1) {flex-basis: 50%;}
div div:nth-child(2) {flex-basis: 100px;}
div div:nth-child(3) {width: 10px;}
div div:nth-child(4) {width: 10px;}
div div:nth-child(5) {flex-basis: 10px;}
.g2 {width:300px;}
.g3 {width:200px;}
.g4 {width:100px;}
</style>
flex 彈性伸縮樣式縮寫
flex
是 flex-grow
、flex-shrink
和 flex-basis
三個樣式屬性的縮寫樣式,三個樣式之間使用「空白分隔」,這個樣式屬性作用於「彈性項目」,沒有繼承特性,寫法如下:
div {
flex: flex-grow flex-shrink flex-basis;
/* 擴展 縮小 基礎 */
}
使用 flex
時除了撰寫三個屬性值,也可以透過四種「關鍵字」對應預設的縮寫屬性值,預設值為 initial
,下方列出四種關鍵字對應的屬性值:
關鍵字 | 對應屬性值 | 彈性項目總長未超過容器時 | 彈性項目總長溢出容器時 |
---|---|---|---|
initial | 0 1 auto | 維持原寬度 ( 無彈性 ) | 縮小填滿容器 |
auto | 1 1 auto | 擴展填滿容器 | 縮小填滿容器 |
none | 0 0 auto | 維持原寬度 ( 無彈性 ) | 維持原寬度 ( 無彈性 ) |
非負值數字 | 非負值數字 0 0 | 擴展填滿容器 | 消失 |
下方範例展示使用 0 作為關鍵字所產生的彈性伸縮效果,由於藍綠紫三個 div 加起來寬度為 100px,所以剩餘的 100px 就由紅黃兩個 div 按照比例分配,因為設定 flex: 0
之後第三個數值為 0,等於 flex-basis: 0
,在其他彈性項目不為 0 的狀態下,若還有剩餘空間就會按照比例分配,若沒有剩餘空間,該彈性項目就會消失。
<!-- HTML 程式碼-->
<h3>彈性容器空間 > 彈性項目總寬度</h3>
<div class="f g1"><div></div><div></div><div></div><div></div><div></div></div>
<div class="f g2"><div></div><div></div><div></div><div></div><div></div></div>
<h3>彈性容器空間 < 彈性項目總寬度</h3>
<div class="f g3"><div></div><div></div><div></div><div></div><div></div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 400px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {padding: 5px 0px;}
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
.g1 div {width: 100px;} /* g1 的彈性項目預設寬度 100px,容器還剩餘 100px */
.g1 div:nth-child(1) {flex: 1;} /* 等於 flex: 1 0 0; */
.g1 div:nth-child(2) {flex: 2;} /* 等於 flex: 2 0 0; */
.g2 div {width: 100px;} /* g2 的彈性項目預設寬度 100px,容器還剩餘 100px */
.g2 div:nth-child(1) {flex: 1 0 0;} /* 等於 flex: 1; */
.g2 div:nth-child(2) {flex: 2 0 0;} /* 等於 flex: 2; */
.g3 div {width: 200px;} /* g3 的彈性項目預設寬度 200px,溢出容器 100px */
.g3 div:nth-child(1) {flex: 1;} /* 等於 flex: 1 0 0; */
.g3 div:nth-child(2) {flex: 2;} /* 等於 flex: 2 0 0; */
</style>
下方範例展示了一個「非常彈性」的彈性排版,搭配「文字換行」和「內容溢出裁切」的樣式,就能在不同寬度的父元素顯示狀態下,展現不同的彈性項目寬度,實現的效果如下:
元素 | 樣式 | 彈性容器有空間時 | 溢出彈性容器空間時 |
---|---|---|---|
紅色 div | flex: 1 0 0; |
按照紅 1 黃 5 增加空間 | 消失 |
黃色 div | flex: 5 0 0; |
按照紅 1 黃 5 增加空間 | 消失 |
藍色 div | flex: 0 1 80px; |
維持 50px | 按照藍 1 綠 5 扣掉空間 |
綠色 div | flex: 0 5 80px; |
維持 100px | 按照藍 1 綠 5 扣掉空間 |
紫色 div | flex: 0 0 50%; |
隨時保持 50% 容器寬度 | 隨時保持 50% 容器寬度 |
<!-- HTML 程式碼-->
<div class="f"><div>oxxo</div><div>oxxo</div><div>oxxo</div><div>oxxo</div><div>oxxo</div></div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 300px;
height: 100px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
resize: both; /* 可用滑鼠拖拉縮放 div */
overflow: auto; /* 搭配 resize 一起用 */
}
div div {
padding: 5px 0px;
width: 60px;
overflow-wrap:break-word;
overflow: hidden;
}
div div:nth-child(1) {background: #f55;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #a6f;}
div div:nth-child(1) {flex: 1 0 0;}
div div:nth-child(2) {flex: 5 0 0;}
div div:nth-child(3) {flex: 0 1 50px;}
div div:nth-child(4) {flex: 0 5 100px;}
div div:nth-child(5) {flex: 0 0 50%;}
</style>
order 彈性項目順序位置
order
樣式屬性是作用於彈性項目的樣式屬性,可以「改變彈性項目的位置」,屬性值使用「無單位的整數」,預設值為 0,數字越小越靠近主軸起始點 ( Main Start ),下方的範例會改變原本 1~9 的順序。
<!-- HTML 程式碼-->
<div class="f">
<div class="o3">1</div><div class="o4">2</div><div class="o1">3</div><div class="o5">4</div><div class="o2">5</div><div class="o9">6</div><div class="o8">7</div><div class="o7">8</div><div class="o6">9</div>
</div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 300px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {
padding: 5px 0px;
flex-grow: 1;
text-align: center;
}
div div:nth-child(1) {background: #f33;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #f9f;}
div div:nth-child(6) {background: #f80;}
div div:nth-child(7) {background: #6f6;}
div div:nth-child(8) {background: #ccc;}
div div:nth-child(9) {background: #ff0;}
.o1 {order: 1;}
.o2 {order: 2;}
.o3 {order: 3;}
.o4 {order: 4;}
.o5 {order: 5;}
.o6 {order: 6;}
.o7 {order: 7;}
.o8 {order: 8;}
.o9 {order: 9;}
</style>
使用 order
時需要注意,透過 CSS 選擇器選取到的元素會被歸類為「同一個順序」,因此若選擇了多個元素,這些元素會一起移動,下方範例會透過 CSS 選擇器,將偶數元素的 order
設定為 2,將奇數元素的 order
設定為 3,就能讓偶數放在前面,奇數放在後面。
<!-- HTML 程式碼-->
<div class="f">
<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>
</div>
<!-- CSS 程式碼 -->
<style>
.f {
width: 300px;
height: 50px;
border: 1px solid #000;
display: flex;
font-size: 24px;
margin: 20px ;
}
div div {
padding: 5px 0px;
flex-grow: 1;
text-align: center;
}
div div:nth-child(1) {background: #f33;}
div div:nth-child(2) {background: #fb0;}
div div:nth-child(3) {background: #4cf;}
div div:nth-child(4) {background: #0b0;}
div div:nth-child(5) {background: #f9f;}
div div:nth-child(6) {background: #f80;}
div div:nth-child(7) {background: #6f6;}
div div:nth-child(8) {background: #ccc;}
div div:nth-child(9) {background: #ff0;}
div div:nth-child(2n) {order: 2;}
div div:nth-child(2n-1) {order: 3;}
</style>
小結
這篇教學介紹的 flex
、flex-grow
、flex-shrink
和 flex-basis
是可以充分發揮 Flexbox 最大效益的樣式屬性,透過這些樣式屬性,就能產生自動適應不同父元素寬度的彈性項目,是相當方便好用的樣式屬性!
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~