在開發移動端頁面的時候,出去佈局方便和減少程式碼量的考慮,使用了 Flexbox 的佈局方式,在其中也遇到了一些問題,簡單記錄下。
什麼是 Flexbox
說到 Flexbox,大家應該都不陌生,網路上也有 N 多的教程。但是在這裡還是簡單說一下,就當回顧知識了吧。
CSS 2.1 定義了四種佈局模式 ― 由一個盒與其兄弟、祖先盒的關係決定其尺寸與位置的演算法:
- 塊佈局 ― 為了呈現文件而設計出來的佈局模式;
- 行內佈局 ― 為了呈現文字而設計出來的佈局模式;
- 表格佈局 ― 為了用格子呈現 2D 資料而設計出來的佈局模式;
- 定位佈局 ― 為了非常直接地定位元素而設計出來的佈局模式,定位元素基本與其他元素毫無關。
而 Flexbox(伸縮佈局)是為了呈現複雜的應用與頁面而設計出來的,一種更加方便有效,能夠在未知或者動態尺寸的情況下自由分配容器空間的佈局方式。
要說明 Flexbox 的佈局模型,就必須要放規範上的這張圖:
- main axis(主軸)
- main dimension(主軸方向)
- The main axis of a flex container is the primary axis along which flex items are laid out. It extends in the main dimension.
- 主軸是伸縮專案在伸縮容器裡分佈所遵循的主要軸線,在主軸方向上延伸。
- main-start(主軸起點)
- main-end(主軸終點)
- The flex items are placed within the container starting on the main-start side and going toward the main-end side.
- 伸縮專案從容器的主軸起點開始放置,直到主軸終點。
- main size(主軸尺寸)
- main size property(主軸尺寸屬性)
- A flex item’s width or height, whichever is in the main dimension, is the item’s main size. The flex item’s main size property is either the width or height property, whichever is in the main dimension.
- 伸縮專案在主軸方向上的長或者寬是這個專案的主軸尺寸。一個伸縮專案的主軸屬性是在主軸方向上的長或者寬屬性。
- cross axis(側軸)
- cross dimension(側軸方向)
- The axis perpendicular to the main axis is called the cross axis. It extends in the cross dimension.
- 和主軸垂直的軸叫做側軸,它在側軸方向上延伸。
- cross-start(側軸起點)
- cross-end(側軸終點)
- Flex lines are filled with items and placed into the container starting on the cross-start side of the flex container and going toward the cross-end side.
- 包含伸縮元素的伸縮行從容器的側軸起點開始放置,直到側軸終點。
- cross size(側軸尺寸)
- cross size property(側軸尺寸屬性)
- The width or height of a flex item, whichever is in the cross dimension, is the item’s cross size. The cross size property is whichever of width or height that is in the cross dimension.
- 伸縮專案在側軸方向上的長或者寬是它的側軸尺寸。側軸尺寸屬性則是在側軸方向上的長或者寬屬性。
使用 Flexbox
現在大部分的主流瀏覽器都已經支援了 Flexbox 或者它的舊版語法。如果是使用在移動端,基本上是都支援的。為了相容新老版本的語法,可以這樣使用( Less ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//父元素 .flex-box() { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; } //子元素 .flex(@v) { -webkit-box-flex: @v; -moz-box-flex: @v; -webkit-flex: @v; -ms-flex: @v; flex: @v; } |
為子元素設定了 flex: 1 ,這樣容器裡面的子元素可以均分容器的空間。當然,可以為某個子元素指定一個寬度,這樣剩下的子元素就會平分剩下的空間。
如下圖中的品牌牆:
flex-basis
這個屬性,還是要稍微說一說的。這個屬性是新版規範裡面提到的屬性。它用來描述伸縮元素( flex-item )的初始主軸尺寸和基準值,也就是在根據伸縮比率計算剩餘空間分佈之前的尺寸值,如果在
flex 中省略了這個值,則預設值是 0
, 注意沒有單位 。它的另一個取值是
auto ,這個時候,元素的初始主軸長度和基準值就是它本身的主軸長度,即取決於本身的內容長度。
兩個取值的區別如下圖:
看圖更容易理解一些:值為 0
時,元素分配的是容器的空間。而當值為 auto
時,它分配的是減去元素內容之後剩餘的容器空間。
在值為 auto
時,它的表現跟老版 Flex 規範的伸縮比例表現是一致的,如果盒子內容大小不一致,則每個盒子最後分配的空間大小也不一致。
所以,在處理這個顯示異常時,要在元素上加一個 width: 0%; 來使其表現的正常。實際上, flex-basis: 0; 的行為就是為元素加上一個類似 width: 0%; 的屬性,來分配容器空間。
Flexbox 這個模組有很多的屬性,這裡只介紹最基本的使用,更多內容詳見規範或者 Google。
需要注意的點
- 低版本安卓下大多用的是老版本的規範,所以會導致一些問題:
- 在使用比例伸縮時會因為盒子內容大小不等導致內容無法等分的問題,這個時候可以為這個元素新增
width: 0%;
將其原始大小設為 0(比如 UC 瀏覽器,魅族 MX4,三星 N7100); - 舊版要求伸縮元素( flex-item )必須是塊級元素,所以 inline 元素需要設定
display: block;
才可以正常顯示。有部分國產手機的瀏覽器上就是這樣的(比如:Vivo X3SW); - Flex item 裡面如果有一個塊元素,設定了 margin-top,會出現溢位的問題,表現就是 margin 無效。需要在這個元素上新增 overflow:hidden; 來使其正常顯示。
- 在使用比例伸縮時會因為盒子內容大小不等導致內容無法等分的問題,這個時候可以為這個元素新增
- 因為 Flexbox 有新版和舊版規範,新版的有些屬性(比如:
flex-wrap
),老版規範下並不支援,出於相容性,最好避免使用; -
text-overflow: ellipsis; 在
display: flex;
元素上是沒有效果的。
By the way
還有一個有用的 CSS 屬性,在移動端已經基本支援了,就是 box-sizing: border-box;
。它在使用 padding
時非常有用,可以避免 width
,padding
的計算。可以這樣子用:
1 2 3 4 5 |
.box-sizing(@v) { -webkit-box-sizing: @v; -moz-box-sizing: @v; box-sizing: @v; } |
不過,要注意,在這種盒模型下,邊框的寬度也會算在寬度裡。