Flex入坑指南

彈性佈局flex是一個幾年前的CSS屬性了,說它解放了一部分生產力不爲過。至少解放了很多CSS佈局相關的面試題 :)
以前網上流行的各類XX佈局,什麼postion: absolute+marginfloat+padding,各類均可以使用flex來取代之。
早兩年在使用的時候,仍是會擔憂有兼容性問題的,某些手機在使用了auto-prefixer之後依然會出現不兼容的問題。
好在如今已是2018年了,沒必要再擔憂那些老舊的設備,但願這篇文章能幫你加深對flex的認識。css

準備工做

首先,flex被稱爲一個彈性盒模型,也有稱彈性佈局的。
總之,盒子也好、佈局也罷,咱們老是須要有一個容器Container的:html

<div class="container"></div>

以及若是單純的只是一個容器的話,是沒有任何意義的。
因此咱們還須要有一些內容:git

<div class="contianer">
  <div class="item"></div>
  <div class="item"></div>
</div>

下邊的全部例子基本都是基於以上DOM結構來作的。github

基本語法

如今咱們已經有一個能夠用來寫flex佈局的html結構。
接下來就是一個最基礎的flex佈局的實現:面試

<style>
  .container {
    display: flex;
    height: 50px;

    color: #fff;
    border: 1px solid #03a9f4;
  }

  .item {
    flex: 1;

    text-align: center;
    background: #03a9f4;
  }
</style>
<div class="contianer">
  <div class="item"></div>
  <div class="item"></div>
</div>

咱們在容器上使用display: flex來告訴瀏覽器,這是一個flex佈局的開始。
而後給全部的item添加一個flex: 1的屬性,來代表,咱們這裏邊全部的子元素會沿着主軸平分全部的區域,就這樣,咱們已經實現了一個多列等寬佈局。 瀏覽器

關於flex,最重要的就是要記住他有兩條軸線(主軸、交叉軸),絕大部分屬性都是依賴於軸線的方向。
ide

圖片來自 MDN

由於flex佈局分爲了容器和內容兩塊,各自有各自的屬性,因此就先從容器類的提及。佈局

容器相關的flex屬性

實現上邊的需求,是依賴於不少默認屬性值。
好比,爲何咱們的子元素會橫向的進行分割空間,而不是豎向的,這裏就用到了一個屬性的默認值:post

flex-direction

flex-direction用於定義flex佈局中的主軸方向。
默認取值爲row,是橫向的,表示從左到右,也就是說咱們的全部子元素會按照從左到右的順序進行排列。
咱們能夠經過設置值爲column來改變主軸的方向,將其修改成從上到下。(改變flex-direction的值會影響到一些相關的屬性,會在下邊說到) flex

flex-direction共有四個有效值可選:

  1. row 默認值,從左到右
  2. row-reverse 從右到左
  3. column 從上到下
  4. column-reverse 從下到上

P.S. 在React-Native中默認的主軸方向爲column

因此說flex-direction的做用就是:定義容器中元素的排列方向

flex-wrap

該屬性用於定義當子元素沿着主軸超出容器範圍後,應該按照怎樣的規則進行排列。
該屬性只有簡單的三個取值:

  1. wrap 超出主軸範圍後換行顯示,換行方向按照交叉軸的方向來(默認狀況下就是折行到下一行
  2. wrap-reverse 超出主軸範圍後換行顯示,可是方向是交叉軸的反向(也就是默認狀況下第一行會出如今最下邊
  3. nowrap 即便超出容器也不會進行換行,而是嘗試壓縮內部flex元素的寬度(在下邊的子元素相關的屬性會講到

三種取值的示例:
g0no.png

flex-flow

flex-flow是一個簡寫的屬性,適用於上邊提到的flex-directionflex-wrap

語法:

selector {
  flex-flow: <flex-direction> <flex-wrap>;
}

justify-content

這個會定義咱們的子元素如何沿着主軸進行排列,由於咱們上邊是直接填充滿了父元素,不太能看出效果。
因此咱們對代碼進行以下修改:

<style media="screen">
  .container {
    display: flex;
    width: 400px;

    color: #fff;
    border: 1px solid #03a9f4;
  }

  .item {
    /* flex: 1; */
    width: 100px;

    text-align: center;
    background: #03a9f4;
  }
</style>
<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
</div>

將全部的子元素都改成固定的寬度,也就是說,若是父元素有剩餘空間的話,就會空在那裏。
justify-content的默認取值爲normal,也能夠認爲就是start了,也就是根據主軸的方向(flex-direction)堆在起始處。

幾個經常使用的取值:

  1. center 必然首選的是center,可以完美的實現沿主軸居中
  2. flex-start 沿着主軸從行首開始排列
  3. flex-end 沿着主軸從行末開始排列

以及幾個不太經常使用的取值:

  1. space-between 將剩餘空間在子元素中間進行平分,保證沿主軸兩側不會留有空白。
  2. space-around 將剩餘空間均勻的分佈在全部的子元素沿主軸方向的兩側,也就是說,主軸兩側也會有空白,可是必然是中間空白的1/2大小。
  3. space-evenly 將剩餘空間在全部元素之間平均分配,主軸兩側的空白麪積也會與中間的面積相等。

六種效果的示例:
6dn.png

Warning

有一點須要注意,justify-content的取值都是依照flex-direction所定義的主軸方向來展現的。
也就是說,center在默認狀況下用於水平居中,在flex-direction: column-*時,則是做爲垂直居中來展現的。

align-content

一樣的,align-content也是用來控制元素在交叉軸上的排列順序,可是既然會出現兩個屬性(align-itemsalign-content),勢必二者之間會有一些區別。

由於align-content只能做用於多行狀況下的flex佈局,因此取值會更接近額旋轉後的justify-content,一樣的可使用space-between之類的屬性值。

由於取值基本相似,因此再也不重複上邊justify-content所列的表格,直接上效果:
bafa.png

align-items

align-items與上邊的justify-content相似,也適用於定義子元素的排列方式。
不一樣的是,align-items做用於交叉軸(也就是默認flex-direction: row狀況下的從上到下的那根軸線)
目測平時用到的最多的地方就是水平居中吧(我如今懶的:只要有圖標、表單 & 文字 的單行混合,都會選擇align-items: center來實現:)

經常使用的取值:

  1. center 經常使用來作垂直(交叉軸)居中
  2. flex-start 沿着交叉軸的起始位置排列
  3. flex-endflex-start方向相反
  4. stretch 將元素撐滿容器的交叉軸寬度(在默認狀況下,這裏指容器的高度,可是若是單純的說這條軸線,我以爲寬度更合適一些
  5. baseline 將元素按照文本內容的基線進行排列

以上取值的示例:
l6ri.png

align-content與align-items的異同

二者的相同點在於,都是設置元素在交叉軸上的排列順序。
而區別在於如下兩點:

  1. align-content只能應用於多行的狀況下
  2. align-content會將全部的元素認爲是一個總體並進行相應的處理、而align-items則會按照每一行進行處理:

cvld.png

place-content

place-content能夠認爲是justify-contentalign-content的簡寫了(事實上就是

語法爲:

selector {
  place-content: <align-content> <justify-content>;
}

P.S. 若是單行(元素)想要實現居中仍是老老實實的使用align-items+justify-content吧 :)

子元素的屬性們

有關容器的全部屬性都已經列在了上邊,下邊的一些則是在容器內元素設置的屬性。

flex-grow

flex-grow用來控制某個子元素在須要沿主軸填充時所佔的比例,取值爲正數(浮點數也能夠的)。

selector {
  flex-grow: 1;
  flex-grow: 1.5;
}

舉例說明:
若是一個容器中有三個元素,容器剩餘寬度爲100px,三個元素須要進行填充它。
若是其中一個元素設置了flex-grow: 2,而其餘的設置爲1(默認不設置的話,不會去填充剩餘寬度)
則會出現這麼一個狀況,第一個元素佔用50px,而其餘兩個元素各佔用25px

tcd0.png

Warning

這裏須要注意的一點是,flex-grow定義的是對於剩餘寬度的利用。
元素自身佔用的空間不被計算在內,爲了驗證上邊的觀點,咱們進行一個小實驗。
給每個元素設置一個padding-left: 20px,保證元素自身佔用20px的位置,而後分別設置flex-grow來查看最後元素的寬度是多少。

.container {
  display: flex;
  width: 160px;
  height: 20px;
  align-items: stretch;
}

.item {
  flex-grow: 1;
  padding-left: 20px;
}

.item:first-of-type {
  flex-grow: 2;
}

4fc7.png
3jm1.png

咱們給容器設置了寬度爲160px(爲了方便的減去padding-left計算)。
最後獲得的結果,設置了flex-grow: 2的元素寬度爲70px,而設置flex-grow: 1的元素寬度爲45px
在減去了自身的20px之後,50 / 25 === 2 // true

flex-shrink

flex-shrink能夠認爲是與flex-grow相反的一個設置,取值一樣是正數。
用來設置當容器寬度小於全部子元素所佔用寬度時的縮放比例。
好比說,若是咱們的容器寬爲100px,三個元素均爲40px,則會出現容器沒法徹底展現全部子元素的問題。
因此默認的flex會對子元素進行縮放,各個元素要縮放多少,則是根據flex-shrink的配置來獲得的(默認爲1,全部元素平均分攤
就像上邊的例子,若是咱們仍是三個元素,第一個設置了flex-shrink: 2,則最終獲得的結果,第一個元素寬度爲30px,其他兩個元素的寬度爲35px

.container {
  display: flex;
  width: 100px;
  height: 20px;
  align-items: stretch;
}

.item {
  width: 40px;
  /* flex-shrink: 1; it's default value */
  font-size: 0;
  background: #03a9f4;
}

.item:first-of-type {
  flex-shrink: 2;
}

1s06.png
8rro.png

flex-basis

這個屬性用來設置元素在flex容器中所佔據的寬度(默認主軸方向),這個屬性主要是用來讓flex來計算容器是否還有剩餘面積的。
默認取值爲auto,則意味着繼承widthdirection: column時是height)的值。
通常來說不多會去設置這個值。

flex

flex則是上邊三個屬性的簡寫,語法以下:

selector {
  flex: <flex-grow> <flex-shrink> <flex-basis>;
}

通常來說若是要寫簡寫的話,第三個會選擇設置爲auto,也就是獲取元素的width

align-self

效果如同其名字,針對某一個元素設置相似align-items的效果。
取值與align-items一致,好比咱們能夠針對性的實現這樣的效果:

.center :first-child {
  align-self: stretch;
}

.flex-start :first-child {
  align-self: flex-end;
}

.flex-end :first-child {
  align-self: flex-start;
}

.stretch :first-child {
  align-self: center;
}

83evalign-self-example-1

order

以及最後這裏還有一個order屬性,能夠設置在展現上的元素順序。
取值爲一個任意整數。

默認的取值爲1,若是咱們想要後邊的元素提早顯示,能夠設置以下屬性:

.item:last-of-type {
  order: -1;
}

92r4.png

P.S. 這個順序的改變只是顯示上的,不會真正的改變html的結構,好比,你依然不能經過.item:last-of-type ~ .item來獲取它在視覺上後邊的兄弟元素
當order重複時,按照以前的順序排列大小

總結

flex相關的屬性如何拆分之後,並不算太多。
腦海中有主軸和交叉軸的概念以後,應該會變得清晰一些。
關於上述全部屬性的一個簡單總結:

容器相關

屬性名 做用
flex-direction 用來設置主軸的方向,最基礎的屬性,默認從左到右,此屬性一改,下列全部的屬性都要跟着改,真可謂牽一髮而動全身
flex-wrap 設置元素超出容器後的換行規則,默認不換行
justify-content 設置沿主軸的排列規則
align-content 設置沿交叉軸的排列規則
align-items 以行(默認direction狀況下)爲單位,設置沿交叉軸的排列規則

元素相關

屬性名 做用
flex-grow 當容器大於全部元素時,按什麼比例將剩餘空間分配給元素
flex-shrink 當容器小於全部元素時,元素按照什麼比例來縮小本身
flex-basis 不多用的屬性,設置在容器中的寬(高)
align-self 針對某些元素單獨設置align-items相關的效果
order 設置元素在顯示上的順序

簡寫

屬性名 做用
flex-flow flex-directionflex-wrap的簡寫
place-content justify-contentalign-content的簡寫
flex flex-growflex-shrinkflex-basis的簡寫

以及文中全部的示例代碼都在這裏 code here

參考資料

  1. How Flexbox works (此文中的一些gif圖真心贊)
  2. Understanding Flexbox: Everything you need to know
  3. Learn CSS Flexbox in 5 Minutes

P.S. 先立一個flag,後續還會出一篇各類flex的真實場景應用,畢竟,紙上談兵沒有意義

相關文章
相關標籤/搜索