1. 程式人生 > >Finally! I do understand "flex-basis"

Finally! I do understand "flex-basis"

Long, long, long ago,CSS3就支援了flex佈局,現在各家瀏覽器都支援標準的語法了,這裡推薦一篇比較全面的圖文化教程A Complete Guide to Flexbox.

關於Flex佈局,剛開始學習CSS的時候就"複習"了好幾遍,不是我吹,下面的程式碼也是信手拈來.

div {
    display: flex;
    justify-content: space-evenly;
    align-items: center;
}

but,but,but.....,

flex佈局的伸縮子項上支援一個叫做flex-basis的屬性.閱文件無數,我還是從始至終都沒怎麼理解.最近在寫自己的部落格主題

mweb-mine的時候抄了一個樣式flex: 1 1 300px讓我重新想起了flex-basis這個妖精,所以我決定這次一定要收了它.

MDN:flex-basisMDN文件對於此屬性的解釋如下

The flex-basis CSS property sets the initial main size of a flex item. It sets the size of the content box unless otherwise set with box-sizing.

翻譯過來就是:

CSS 屬性 flex-basis 指定了 flex子項元素在主軸方向上的初始大小。如果不使用 box-sizing 來改變盒模型的話,那麼這個屬性就決定了 flex 子項元素的內容盒(content-box)的寬或者高(取決於主軸的方向)的尺寸大小。

讀罷此句,似乎也不知道flex-basis是用來幹什麼的,有人對這個屬性的使用進行了總結,下面的兩句是我認為最精華的兩點:

1.flex-basis allows you to specify the initial/starting size of the element, before anything else is computed. It can either be a percentage or an absolute value.
flex-basis允許您在計算任何其他內容之前指定元素的初始/開始大小。它可以是百分比,也可以是絕對值。
2.flex-basis defines the default size of an element before the remaining space is distributed. It can be a length (e.g. 20%, 5rem, etc.) or a keyword.
flex-basis

定義在分配剩餘空間之前元素的預設大小。它可以是一個長度(例如20%,5rem等)或關鍵字

也許上面的解釋還是比較難懂,下面我們結合w3c的wiki文件中提供的一張圖來說明

我們都知道,flex佈局的最大的特點就是可以自定義如何分配容器剩餘的空間,或者壓縮子項來適應空間的不足.擴充套件比率是由flex-grow設定的,收縮比率是由flex-shrink設定的,伸縮基準是由flex-basis設定的,三個屬性合併的寫法就是flex屬性.如上圖,假設一個場景,伸縮容器的寬度是1000px,伸縮子項item1,item2,item3的width分別是100px,400px;200px.

<div id="container">
  <div class="item1"></div>
  <div class="item2"></div>
  <div class="item3"></div>
</div>
div {
  box-sizing: border-box;
}

#container {
  display: flex;
  box-sizing: content-box;
  margin: auto;
  width: 1000px;
  height: 200px;
  border: 2px solid orange;
  font-size: 1.5rem;
  color: white;
}

.item1 {
  width: 100px;
  background: red;
}
.item2 {
  width: 300px;
  background: green;
}
.item3 {
  width: 200px;
  background: blue;
}

子項的flex屬性預設值為flex: 0 1 auto,即有剩餘空間時也不進行擴充套件,因此其預設的顯示如上圖.容器右側剩餘400px的空間.接下來,我們給子項新增上擴充套件比率flex-grow,讓子項按照1:1:2的比率分配剩餘空間.

.item{
  flex-basis: auto;
}

.item1{
  width: 100px;
  flex-grow: 1;
  background: red;
}
.item2{
  width: 300px;
  flex-grow: 1;
  background: green;

}
.item3{
  width: 200px;
  flex-grow: 2;
  background: blue;
}

上述伸縮基準flex-basis: auto,這個值會在瀏覽器分配空間時計算為元素在主軸方向上的長度屬性,此例子中即為子項的寬度.從上圖可以看出,剩餘空間按照100px: 100px: 200px分別分配給了子項,子項在原有width值上進行了這些疊加.這似乎符合我們常用的習慣,接下來,我們修改一處地方,將所有子項的伸縮基準設定為flex-basis: 0

.item{
  flex-basis: auto;
}


從上圖可以看出實際展示寬度發生了天翻地覆的變化,我們來分析一下這個變化的原因.還記得文章一開始的重點嗎:
flex-basis定義在分配剩餘空間之前元素的預設大小

也就是說,當所有子項設定flex-basis: 0,在分配空間的時候瀏覽器不再關注所有子項原有的寬度(準確的說是:子項在主軸方向的長度),這時剩餘寬度就是1000px - 0px -0px -0px = 1000px,然後直接按照1:1:2的比例分配1000px,所以最終三個子項的寬度分別為: 200px, 200px, 400px.

有一個很形象的例子可以解釋上述空間的分配,解放初期,我國進行過"人民公社化"的嘗試,假設有一個公社有三戶人家,三家各有糧食100kg, 300kg, 200kg,三家各有1,1,2口人,各家各戶把家裡的餘糧全部上交到公社食堂,縣裡又給公社撥了400kg糧食,這樣各家的餘糧都是0,公社共有1000kg的糧食,在食堂吃飯的時候,是按照各戶人口來分配食物的,所以三家分到的食物分別是200kg, 200kg, 400kg

有了上面的準則和介紹,下面的變化應該就能分析出來了.

.item1 {
  width: 100px;
  flex-grow: 1;
  flex-basis: 200px;
  background: red;
}
.item2 {
  width: 300px;
  flex-grow: 1;
  flex-basis: 100px;
  background: green;
}
.item3 {
  width: 200px;
  flex-grow: 2;
  flex-basis: 300px;
  background: blue;
}

在分配空間的時候,子項在主軸上的基準長度,由flex-basis決定,也就是200px, 100px, 300px,剩餘400px按照1:1:2的比例分配,最後寬度200px+100px=300px, 100px+100px=200px, 300px+200px=500px

最後還有兩點需要注意:
1.flex-basis影響的子項在主軸上的伸縮基準值,前面的例子我們預設的flex-direction: row,如果flex-direction: column也有學會以此類推.空間不足的時候子項需要的收縮情況也可以類比出來.

2.需要注意子項的長度還是會受到max-width/min-width(當flex-direction: row)或max-height/min-height的影響,比如給最後一項新增一個max-width:400px

.item1 {
  width: 100px;
  flex-grow: 1;
  flex-basis: 200px;
  background: red;
}
.item2 {
  width: 300px;
  flex-grow: 1;
  flex-basis: 100px;
  background: green;
}
.item3 {
  max-width: 400px;
  width: 200px;
  flex-grow: 2;
  flex-basis: 300px;
  background: blue;
}


因為第三項的最大長度是400px,那就多出來100px,前面兩項按照1:1分配掉