[基礎課程] CSS 教學(四):浮動、佈局、Flex
本篇進入跟版面調整有關的技巧章節,Float 是很常見的浮動觀念,接著佈局章節會提供一些例子進行設計,最後是非常重要且主流的 flexbox 觀念。也就是網頁排版的重點都包含在這篇文章了。另外其實還有 Grid 跟 RWD 部分將之後由 Bootstrap 去深入學習。
浮動 float
float 參數會讓元素產生一種浮動行為,而這個行為會變成 block 性質並緊貼在指定處(像磁鐵一樣)。
- 在設定 float 前需先考慮標籤的排列順序,因為受到 float 屬性的標籤會影響到彼此之間的預設位置。
- 在設定某個標籤 float 時,需指定標籤寬度(否則將以內容為寬值),可以是絕對單位 (px)、相對單位 (em、rem)、比例單位 (%)。
- 瀏覽器會將受浮動屬性效果的行內元素視同等於
區塊 block 元素
。 - Float 可做文繞圖但有原始順序限制,也就是撰寫 HTML 的順序。
- 用來排版浮動區塊等級元素時,要設定該元素的 width 屬性(圖片不需要,已具備寬),這點排版很重要。
- 一般浮動用在文繞圖、二欄、三欄、選單。
- 停止浮動 clear:both。
<style> |
影響父容器的高度消失
float 本身會脫離父層內的文字流,若父元素沒有高度也沒有其他東西能撐出高度時,這意謂著現在裡面的子元素都是 float。因為脫離了文字流(抓不到 float 子元素)影響父元素而失去了高度,這點透過父元素設定 border 看出問題。
素材準備:準備代碼以方便下階段的教學練習
- 父層 container 為 960,均分給 3 組 col 並規劃子設定 w300, p10, m10, b5,利用 box-sizing 使排列剛好滿版。
- 搞定滿版之後,指定 col 為 float 並觀察 container 的變化合理性,並試著排除。
<style> |
方法一:父容器設定 overflow
此時只要對父元素設定 overflow:hidden(or auto) 使錯亂溢位的情況重新修正空間,強迫將父元素再次將 float 子元素算入高度。
多添加以下屬性:
.container { |
方法二: 關閉 float
由於 float 會持續運作剩餘浮動空間給之後的浮動元素,因此可以塞入一個區塊同時要求屬性為 clear:{left|right|both}進行關閉浮動的空間分配。
本範例中可以在最後的.col
之下一個標籤添加:
<div class="col">...</div> |
此時因為該屬性 clear 關閉了浮動同時也配給出空間,父容器也能算出整體的自身內容高度。
小技巧:設計 class 規則並善用::after
有時候你不會想對 HTML 添加多餘的元素,我們會習慣設計一個 class 公式能夠對父容器有效(拉回父容器高度),也能對排在後面非浮動之元素有效(不用寫 style 的 clear)。
.clearfix::before,.clearfix::after{ |
如案例中:若要修正父容器 div.container.clearfix
;若要設定非浮動元素 div.clearfix
。
排版布局 layout
這裡將著重如何將區塊進行畫面排版的方式與技巧。
兩欄式
將畫面為兩個區塊並排成兩欄位,共以下多種狀況與不同處理作法。
左側 A {float:left} 與 右側 B {margin-left}
- 分配 AB 區塊的固定寬度。
- 將 A 區塊進行 float 靠左側浮起來,此時 B 區塊仍在原處。但因為文繞凸效果所以文字被擠壓出來。
- 將 B 區塊故意修正推回適合的新位置,達成兩個區塊不重疊,一個浮於上面一個右推定位。
<style> |
右側 A {float:right} 與 左側 B
- 分配 AB 區塊的固定寬度。
- 將 A 區塊進行 float 靠右側浮起來,此時 B 區塊仍在原處且剛好的寬度使畫面合理。
<style> |
左側 A {float:left} 與 右側 B {float:left}
因為兩者都已形成浮動元素,第一個浮動元素依條件靠齊,而剩餘的浮動空間提供給下一個浮動元素貼齊,因此不會去考慮父容器 (body) 的空間分配。
<style> |
左側 A {float:left} 與 右側 B {float:right}
同上,A 浮動靠齊左側後剩餘空間留給其他浮動元素使用。B 浮動依條件靠右使用,若空間不足則擠壓至下一行重新占用。
<style> |
左側 A {float:left} 與 右側 B {overflow:auto|hidden}
A 浮動定位後,B 產生了溢位上的空間錯亂,設定 B autoflow:auto 修正因浮動所產生的溢位。
<style> |
三欄式
將畫面為三個區塊並排成三欄位,共以下多種狀況與不同處理作法。
左 A {float:left} & 中 C {margin:0 20%} & 右 B {float:right}
注意標籤排列順序,先是 float 的兩欄 sidebar1、sidebar2,接著才是 main,浮動欄位順序優先。
<style> |
左 A {float:left} & 中 C {float}:left} & 右 B {float:right}
全部都使用浮動元素,靠齊方式略不同,須注意順序。
<style> |
左 A {float:left} & 中 C {float}:left} & 右 B {float:left}
全部都使用浮動元素,靠齊方式全為左側。
<style> |
小節練習 - Layout by Float
- 設計一個 1024x768 的版面 container 且對齊 body 水平垂直置中,並包含以下四個區塊 header、left、right、footer。
- 區塊顏色自由設計。
- 字型需用微軟正黑體。
- 文字需水平、垂直置中。
<div class="container"> |
- 先設計 .container 的外觀屬性,先跳過垂直水平置中的要求
- 其中四個區塊設定 line-height 與 height 同高可以形成文字垂直居中的效果。
.container{
font-family: "Microsoft JhengHei";
width: 1024px;
height: 768px;
border: 1px solid #000;
color: white;
font-size: 3rem;
text-align: center;
}
.header {
width: 1024px;
height: 100px;
background: #000;
/* line-height: 100px; */
}
.left {
width: 200px;
height: 568px;
background: #aaa;
float: left;
/* line-height: 568px; */
}
.right {
width: 824px;
height: 568px;
background: #777;
float: right;
/* line-height: 568px; */
}
.footer {
width: 1024px;
height: 100px;
background: #000;
clear: both;
/* line-height: 100px; */
} - 最後,垂直致中的
.container
有三種方法/* ver1:
因為已經有寬高不如讓 margin 去自動算,但先用 fixed(或 absolute) 才能有絕對定位去抓邊界。
*/
.container{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
/* ver2:
直接算出畫面中心點,但先用 fixed(或 absolute) 才能有絕對定位去抓邊界。
*/
.container{
position: fixed;
left: 50%;
top: 50%;
margin-left: -512px;
margin-top: -384px;
/*
也可以不要用 margin 去反退位置,改用
transform: translate(-50%, -50%);
會更快
*/
}
/* ver3:
使用 flexbox,對父容器 body 設計
*/
body{
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
彈性盒 FlexBox
- 讓排版端喲端喲的彈性自動算。垂直對齊超簡單,Bootstrap CSS 框架也在用。
- float 會讓外盒高度消失掉,flex 會讓外盒的高度保持設定。
屬性 | 單位 | 宣告在哪 | 說明效果 |
---|---|---|---|
flex-direction | row|column | 父容器 | 決定主軸的排列方式:橫向|直向 |
flex-wrap | 選項 | 父容器 | 強制一行或依容器排成多行。 |
justify-content | 選項 | 父容器 | 主軸內容的水平對齊方式:靠左、靠右、置中、分散、平均、空間 |
align-items | 選項 | 父容器 | 交叉軸 (cross axis) 整體的縱向對齊方式:頂端、底部、填滿、基準線、中線 |
align-self | 同 align-items | 子項目 | 設定單一元素的縱向對齊方式,會覆寫父層align-items 的設定。 |
align-content | 同 align-items | 父容器 | 在容器允許多行狀態(指定 flex-wrap:warp) 時,特別指定主軸的縱向對齊方式分配 |
flex-grow | 數字 | 子項目 | RWD 分配公式依膨脹倍數計算 |
flex-shrink | 數字 | 子項目 | RWD 分配公式依收縮倍數計算 |
flex-basis | 長度單位 | 子項目 | RWD 分配公式依彈性係數指定各多少 |
order | 數字 | 子項目 | 控制排列順序,預設為 0。start 開始由小到大排序至 end |
當父容器為
display: flex
(或inline-flex
) 情況下,可進行以上設定(僅介紹到常用的屬性)。
前導觀念
Flexbox 是 CSS3 推出的盒子模型 ( box model ) 且具備靈活彈性 ( Flexible Box ),彈性盒是 CSS 裡很重要的觀念,當宣告一個標籤容器為彈性盒 flex (或 inline-flex) 時,該元素就成為彈性容器(flex container)。
而該容器內的子元素都會變成彈性項目 (flex item),無論是區塊(block)或行內(inline)元素(不論是 p 或 span 都一樣,頂多像是 p 預設的 margin 值導致邊界範圍不同而異)。
彈性容器中的子項目可以自動適應寬度,就像使用了百分比單位的元素
。值得注意的是如果子項目是清單(ul、ol),他的子元素 li 並不會變成彈性項目。
宣告父容器 display:flex 時若同時有指定高度時,子項目也會以此高度為數據,這是因為 align-items 預設為 stretch 關係(充滿整個容器)。
主軸和交叉軸
與一般的盒子模型不同的地方,在於 Flexbox 的盒子模型具有:
- 水平(主)軸與垂直(交叉)軸 ( main axis、cross axis )
- 水平主軸部分有區分為:起點與終點 ( main start、main end )
- 垂直交叉軸部分有區分為:起點與終點 ( cross start、cross end )
- 子項目則有水平尺寸與垂直尺寸 ( main size、cross size )
這些都是相當重要的佈局規劃考量。 flexbox 全是靠主(水平)軸(main axis)和交叉(垂直)軸(cross axis)進行空間分配。
父容器的預設值
新宣告一個 flex 容器時,其初始的預設值如下:
.flex { |
flex 與 inline-flex 差異
flex 本身算是一種 block 現象,未指定寬度時會塞滿寬度的現象;inline-flex 則是 inline-block 現象,可以接著後面排 inline 性質之元素。
<style> |
範例:flexbox’s menu
將標籤 nav 設定為 display:flex 後就成為了彈性盒之父容器,所有子元素也都成為彈性項目,本身 a 元素的特性仍然不變,但從呈現的角度上已變成彈性項目且不再是行內(inline),因此也不會發生經典的 4px 空白空隙問題。
<style> |
父屬性複合 flex-flow (flex-direction, flex-wrap)
flex 的流向設定,為同時設定 flex-direction 與 flex-wrap 的複合屬性,主要是定義容器內項目的排列方向與換行規則。
flex-flow: flex-direction flex-wrap;
,為複合屬性,一次縮寫兩筆屬性。
flex-direction
設定主軸的排列方式採用水平或垂直排列。row 彈性項目逐一水平排列
,column 彈性項目逐一垂直排列
,多了-reverse 則是反向觀念。
試著切換不同的 flex-direction 看看效果差異:
<style> |
flex-wrap
設定彈性項目位置超過容器時是否允許換行。
flex-wrap | 說明 |
---|---|
nowrap(預設) | 項目有寬度且總寬超過容器,不拆行,項目彈性自縮。 |
wrap | 項目有寬度且總寬超過容器,拆行,項目保持原尺寸。 |
wrap-reverse | 項目有寬度且總寬超過容器,反向往上拆行,項目保持原尺寸。 |
.flex { |
父屬性 justify-content
定義了容器主軸上的子項目的對齊方式,宣告在父容器上。
justify-content | 說明 |
---|---|
flex-start | 預設,靠左對齊 |
flex-end | 靠右對齊 |
center | 置中對齊 |
space-between | (彈性項目佔據最左最右,平均分配項目之間的空間 |
space-around | 將空間分配在彈性項目周圍 |
.flex { |
範例:space-between 的間隙應用
justify-content: space-between
這個效果,如果早期用一般 CSS 排版時你需要對所有元素的nth-*, first-child, last-child
個別指定間隙 (gutters) 較為麻煩。
<style> |
父屬性 align-items
可解讀為主軸的另一條交線,交叉軸 (cross axis) 的垂直對齊方式(填滿、頂端、底部、中線、基準線)。宣告在父容器使子項目會縱向排列。
align-items | 說明 |
---|---|
stretch(預設) | 不設定寬、高、間距則充滿整個容器。 |
flex-start | 頂端對齊 |
flex-end | 底部對齊 |
center | 中線對齊 |
baseline | 基準線(內容之文字)對齊 |
stretch 可以拉長到 100% 的 cross-size(縱向尺寸),但如果已設定固定尺寸像是 min-height, min-width, max-height, width, height 則這些有高優先權。也就是當某個子項目在交軸方向上有設定了尺寸,stretch 就不會去控制該項目尺寸。
<style> |
子屬性 align-self
對子項目作用的單一效果且優先高於父容器的 align-items 設定,可改變自身的對齊方式(覆蓋 align-items 效果)。即使父層沒有設定 align-items 不影響子項目仍可使用 align-self。
同前一組範例,對某一子項目添加練習:
.blue { |
父屬性 align-content
當容器的採用 nowrap 排列 item 時,只有一排會用滿容器的交叉軸空間;當容器是 wrap 排列 item 時(指定 flex-wrap:wrap),則會是多排且平均分配(預設 stretch) 容器的交叉軸空間。換句話說,align-content 是拿來控制多行下的分配方式。這跟 align-item 或 align-self 沒有關聯只是另外去定義多行的分配規則。
<style> |
align-content 只能是 flex-wrap:wrap 模式下才有效。
子複合屬性 flex (flex-grow, flex-shrink, flex-basis)
宣告在彈性項目上的伸展比例、壓縮比例、基本大小的規則公式,使得能在容器內如何分配寬度比例或是自動調整自身項目寬度。flex 為複合屬性包含了三種不同方式。
flex: flex-grow flex-shrink flex-basis;
,為複合屬性 一次縮寫三項屬性。
flex-grow
flex 項目的膨脹係數(預設為 0=不膨脹分配),其值輸入數字(沒有負數)而非單位。當容器夠大的情況下扣除每個項目指定的寬度後,剩下的空間依比例分配回項目身上產生了項目擴展膨脹。即使主軸方向為垂直 (flex-direction: column),也是同樣道理分配高度。
<style> |
flex-shrink
flex 項目的收縮係數(預設為 1= 壓縮基本比例),其值輸入數字(沒有負數)而非單位,設定為 0 則不允許壓縮。當容器過小的情況下且扣除項目總寬後已無空間時,將開始壓縮項目寬度直到最低限度(像是內容文字),壓縮過程依據比例分配。即使主軸方向為垂直 (flex-direction: column),也是同樣道理分配高度。
舉例說明:
- 項目寬度 100,外距 10。因此 3 筆項目總長為 120*3=360
- 當父容器低於 360 因沒有空間,會開始壓縮項目排出空間,根據 0,1,2 比例去吃空間壓縮
- 假設容器空間剩下 270 時,需要從項目身上取出 90 空間量
- 0 : 固定,所以還是 100,margin=10
- 1 : 被吃走 1/5(=18),所以剩下 82,margin=10
- 2 : 被吃走 4/5(=72),所以剩下 28,margin=10
<style> |
flex-basis
flex 項目的主軸空間尺寸(預設為 auto = 無指定),也就是該項目的顯示區域分配值,單位採用 px,em,%… 等。決定項目本身的顯示尺寸依據來源為 content(內容寬)、width 值、flex-basis 值,將從這些屬性取某一項(有優先性)取為基本寬度。
content < width < flex-basis (limted by max|min-width)
- 當 flex-basis 存在,項目尺寸將不參考 width 值(也就是不需要去設計 width 值)。
- flex-basis 會遵守 min-width 與 max-width 規則限制
- 如果 flex-basis 未指定,會以項目 width 屬性為大小
- 如果 width 未指定,會以項目本身的 content 為大小
使用 flex 彈性盒你應該習慣使用 flex-basis 去分配項目的空間基本尺寸,而不是傳統的去誤會使用 width 或 height 來設計尺寸。width(height) 跟 flex-basis 兩者都有存在的意義,當成為 flex 的項目時需考量容器大小跟配置方式而不固定之組合,像是因主軸方向而導致對立方向的尺寸就需要 width(或 height) 來協助。
舉例:Bootstrap 裡的 flex 屬性
.col-sm-4 { |
子屬性 order
能重新調整單一項目在容器主軸上的出場順序進行排列由小至大(預設為 0),其值輸入數字(可負數)而非單位。同值時下將參考 HTML 順序。
.red { |
總結案例
這裡提供兩個 flex 學習網站抓準 flex 技巧,做一下最後練習。
透過遊戲方式共 24 關卡,學習 CSS 的 flex box 技巧,全球著名的練習遊戲。
透過遊戲方式共 12 關卡,學習 CSS 的 flex box 技巧,幫助思考並加強 CSS 排版上的各種雜症。
透過遊戲方式共兩總模式分別為 20 與 30 關卡,來自六角學院出處。
彈性盒置中方式
/* justify-content 為 flex box 水平軸對齊方式 */ |
Flexbox 內的 Margin:auto
在 flexbox 內任何的項目已持有寬尺寸,因此可輕易的使用 margin-right 去推擠至邊界定位。
<style> |