移動端開發小記 - Flexbox
在開發移動端頁面的時候,出去布局方便和減少代碼量的考慮,使用了 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 ):
//父元素 .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的計算。可以這樣子用:
.box-sizing(@v) { -webkit-box-sizing: @v; -moz-box-sizing: @v; box-sizing: @v; }
不過,要注意,在這種盒模型下,邊框的寬度也會算在寬度里。