Flex布局原理介紹

引言

CSS3中的 Flexible Box,或者叫flexbox,是用于排列元素的一種布局模式。

顧名思義,彈性布局中的元素是有伸展和收縮自身的能力的。 相比于原來的布局方式,如float、position,根據盒子模型,就可以計算出元素的展示尺寸(長寬非百分比),除非溢出,否則不依賴于父容器的大小。

而彈性布局中元素的大小是高度依賴父容器的大小的。因為,它所具有的“伸縮性”,目標就是為了撐滿父元素。當然這是在任其“野蠻生長”的情況下,你也可以通過相關css屬性控制其是否撐滿、撐滿什么軸。

彈性布局是一種全新的思維方式,讓很多實現復雜的問題有了更好的理解方式(如垂直居中)。只需要給直接父容器設置為display: flex;,duang~ 子元素就默認具有了可收縮性
Flex的語法規范也曾經有很多版本:

  • 最新版本是display: flex;
  • 中間版本是display: flexbox;
  • 最老版本display: box;

本篇文章側重于flex難理解的點,適合于已經了解過flex的api的童鞋觀看。(api其實就下圖這么多,橙色是常用的)


[](https://alisecued.github.io/2017/01/03/Flex%E5%B8%83%E5%B1%80%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D/#

為何要引入主軸、交叉軸、軸線的概念)為何要引入主軸、交叉軸、軸線的概念

我們首先看一下,CSS布局的發展歷程:


翻開flex的入門教程,首先映入眼簾且比較難懂的就是主軸和交叉軸(對,就是下面這張圖),這是前幾種布局方式都沒有的。



前幾種布局都可以按照人類書寫的方式理解:“從左到右寫,寫不下就往下換行”。

但是flex特點是可以重新定義這種“書寫方式”,你還可以從下到上寫、從右到左寫(見flex-direction屬性),換行也可以從兩個相反的方向換行(見flex-wrap屬性)。所以引入了這個幾個概念方便理解。

瀏覽器的布局方式是:
沿著主軸的方向依次排列,如果要換行,則沿著交叉軸的方向進行換行,每行代表一條軸線。但是,我們可以使用子元素的order屬性對元素進行重新排序。由此可見,flex給子元素提供了很大的靈活性。

主軸、交叉軸可以幫助我們理解這些概念:

  • 重新定義瀏覽器“書寫方式”。
    • flex-direction 改變主軸方向;
    • flex-wrap 改變交叉軸方向

如下圖,主軸和交叉軸的排列組合有4*2 =8 種。


screenshot.png

比如,可以像寫對聯一樣,從上到下豎著書寫,從右到左換行。
(2017新年快樂~)


.container {
    flex-direction: column;
    flex-wrap: wrap-reverse;
}

為了方便表達,本篇文章都使用默認的軸方向。

  • 軸上的元素的排列方式(justify-content, align-items)。

    • justify-content 定義了元素在主軸軸上如何對齊;
    • align-items 定義了元素在交叉軸上如何對齊
    • flex-start: 對齊軸起點;
    • flex-end: 對齊軸終點;
    • center:在軸線上居中;
    • space-between:兩端不帶間距的軸線兩端對齊;
    • space-around: 兩端帶間距的軸線兩端對齊, 且每個子元素之間的間距相同(假設為x)。兩端元素離父元素間距為(x/2)。 注意這個間距既不是margin也不是padding,盒子模型來計算展示方式已經不適用了。
    • baseline:交叉軸特有,基線對齊。
    • stretch:交叉軸特有,有占滿整個主軸高度的意向。當設置了子元素高度為非auto時不生效。
  • 多根軸線時,軸線之間的排列方式(align-content)。align-content的參照軸是交叉軸。其屬性也和上面的justify-content、align-items大同小異:flex-start、flex-end、center、space-between、space-around、stretch。不多做解釋。

元素寬度如何伸縮

能決定元素展示寬度的屬性有: flex-shrink,flex-grow,flex-basis,width,min-width

flex為前三個屬性的縮寫方式,所以常用寫法是flex-shrink,flex-grow,flex-basis統一用flex設置。

常見的flex設置:

| 序號 | 樣式 | flex-grow | flex-shrink | flex-basis |
|: -------------: |:------------:| :------------:|:-----------------:|:---------------:|
| ① |flex默認值| 0 | 1 | auto |
| ② | flex: 1 | 1 | 1 | 0% |
| ③ |flex: auto | 1 | 1 | auto |
| ④ |flex: none | 0 | 0 | auto |

那么,flex-grow和flex-shrink的值會對元素造成什么影響呢?

如下圖所示,當元素允許縮小時,最終展示的效果會是正好撐滿主軸。

在父容器中有三個元素A1,A2,A3,他們都有一個初始寬度(比如設置了width且flex-basis不為0%)。初始寬度在下一小節會詳細講。
如果按照初始寬度放入普通父容器中,那么他們會溢出x個像素(見初始尺寸行)。

當父元素display: flex;,
且A1flex-shrink:1,A2flex-shrink:1,A3flex-shrink:1時,

A1、A2、A3都具有可收縮的特性。

flex-shrink的值表示需要收縮的寬度占總溢出寬度的比例,因此展示尺寸這么算:

  1. 將x平均分為(1+1+2) = 4份,每份寬度為i = x/4

  2. A1的展示尺寸為:A1默認寬度 - i × 1;
    A2的展示尺寸為:A1默認寬度 - i × 1;
    A3的展示尺寸為:A1默認寬度 - i × 2;

同理,當元素不夠撐滿父元素時,需要伸展的寬度也是按照這種方式計算的。只是比例基數變成了剩余空間的寬度。
**如果你希望元素不能伸縮,那么需要設置相應的屬性為0。
如: flex-shrink: 0

flex-basis和width的關系

flex-basis 用于計算上一小節中元素的“初始寬度”。

  • flex-basis為auto時, 初始寬度為元素內容大小或者設置的寬度值(盒子模型中的占用寬度)。
  • flex-basis為像素值時,初始寬度為flex-basis的值。
  • flex-basis為百分比時,初始寬度為占父容器的比例。
  • flex-basis為0或0%時,初始寬度為0。

雖然flex-basis的優先級大于width,但是最后計算的展示尺寸受限于min-width或者max-width

比如,元素A算出來的展示寬度為100px,但是它有個css屬性min-width: 200px;
, 那么最后的展示寬度仍然為200px。但是計算的初始尺寸仍然是由flex-basis決定。

兼容性

caniuse上可以查到,通過加上各種前綴,flex可以兼容到ie10以及以上。
16年年初在實際使用過程中,發現UC的支持性很不好。這次又重新試了一次,新版的UC也能很好的支持flex了。看來flex正在慢慢占領移動端。

幾個案例

通過上面幾小節的描述,可以發現flex用了一種全新的思路來布局。列出幾個常見的案例,以下案例的代碼統一在我的codepen可查看。

1.垂直居中


.container {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

2.一側固定,一側自適應


.container {
    display: flex;
    .sidebar {
        width: 100px;
     }
    .content {
        flex: 1;
     }
}

3.多列等高


多列等高
.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-content: stretch;
}

總結
flex布局是圍繞父元素和軸來進行布局的。這種全新的思路巧妙地只需要簡單幾行代碼就可以實現曾經頭疼的效果,其思路的建立過程非常值得借鑒。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • H5移動端知識點總結 閱讀目錄 移動開發基本知識點 calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇閱讀 4,625評論 0 26
  • 移動開發基本知識點 一.使用rem作為單位 html { font-size: 100px; } @media(m...
    橫沖直撞666閱讀 3,514評論 0 6
  • 前言 溫馨提示:本文較長,圖片較多,本來是想寫一篇 CSS 布局方式的,但是奈何 CSS 布局方式種類太多并且實現...
    sunshine小小倩閱讀 3,173評論 0 59
  • 傳統的網頁布局基于盒裝模型,使用display,position,float屬性來達成各種布局。對于一些特殊的布局...
    exialym閱讀 2,649評論 0 11
  • 前言 FlexBox是css3的一種新的布局方式,天生為解決布局問題而存在的它,比起傳統的布局方式,我們使用Fle...
    zevei閱讀 1,438評論 23 3