轉自:http://zhoon.github.io/css3/2014/08/23/flex.html 感謝他的整理
flex為css的布局帶來了新的時代,作為一個重構工程師,我們再也不用局限於float和position,特別是在移動端,我們可以利用flex輕松實現以往float和psition很難實現甚至是無法實現的布局。 本文主要講解flex的三個子屬性:flex-grow、flex-shrink、flex-basis。他們只是博大精深的flex中的一部分,本文默認你對flex已經有初步的了解,如果不了解,建議先看看這里:http://www.w3cplus.com/blog/666.html。
flex布局發生在父容器和子容器之間。父容器需要有flex的環境(display:flex;),子容器才能根據自身的屬性來布局,簡單的說,就是瓜分父容器的空間。相反就是說如果父容器沒有flex的環境,那么子容器就無法使用flex的規則來划分父容器的空間。
講到瓜分父容器的空看,那么首先需要講一個很重要的詞:剩余空間。
什么是剩余空間呢?具備flex環境的父容器,通常是有一條主軸和一條側軸,默認情況下主軸就是水平從左向右的,側軸是垂直從上到下的(類似書寫模式)。 剩余空間就是父容器在主軸的方向上還有多少可用的空間。比如看下面這段html結構:
container就是父容器,B1 B2 B3就是子容器,假如container的width是500px,那么剩余空間就是:500px - B1.width - B2.width - B3.width。嗯就是這么簡單!
##flex-grow (default:0) 知道了剩余空間的概念,首先來看一下flex-grow。上面那個例子,我們假設container的width是500px,現在我們再假設B1、B2、B3的width是100px,那么剩余空間就是500-100*3=200。 知道了剩余空間有什么用呢?這個時候flex-grow就該出場了,假如我們這個時候對B1設置flex-grow:1,那么我們會發現,B1把B2和B3都擠到右邊了,也就是說剩余的200px空間都被B1占據了,所以此時B1的width比實際設置的值要大。
所以這里flex-grow的意思已經很明顯了,就是索取父容器的剩余空間,默認值是0,就是三個子容器都不索取剩余空間。但是當B1設置為1的時候,剩余空間就會被分成一份,然后都給了B1。 如果此時B2設置了flex-grow:2,那么說明B2也參與到瓜分剩余空間中來,並且他是占據了剩余空間中的2份,那么此時父容器就會把剩余空間分為3份,然后1份給到B1,2份給到B2,如下面這樣子。
##flex-basis (default:auto) 初次見flex-basis這個屬性,還挺疑惑的,不知道它是用來干嘛的。 后來研究發發現,這個屬性值的作用也就是width的替代品。 如果子容器設置了flex-basis或者width,那么在分配空間之前,他們會先跟父容器預約這么多的空間,然后剩下的才是歸入到剩余空間,然后父容器再把剩余空間分配給設置了flex-grow的容器。 如果同時設置flex-basis和width,那么width屬性會被覆蓋,也就是說flex-basis的優先級比width高。有一點需要注意,如果flex-basis和width其中有一個是auto,那么另外一個非auto的屬性優先級會更高。
tips:flex-basis和width為auto值,那最后的空間就是根據內容多少來定的,內容多占據的水平空間就多。
##flex-shrink (default:1) 好了,上面講了這么多,你們應該都明白了把。 有人會想,不就這樣嘛,很容易啊,不就是剩余空間的分配嗎?
是的,上面講的都是剩余空間的分配。但是,你有沒有想過還有沒有其他的情況呢?可以發現,上面講的例子B1 B2 B3的寬度總和都是沒有超過父容器的寬度的。 那如果三個子容器的寬度和超過父容器的寬度呢?那還有剩余空間可以分配嗎,此時瀏覽器又是怎么處理呢?請看下面:
tips:flex環境默認是不換行的,即使父容器寬度不夠也不會,除非設置flex-wrap來換行
此時我們會發現,B1設置的flex-grow沒有作用,不但沒有獲取到剩余空間,他的空間甚至是比他定義的300px還要小,而且我們發現B2和B3的空間也相應的被壓縮了。 那么這里的問題就是:1、為什么flex-grow沒有作用,反而被壓縮呢?2、三個容器的壓縮比例是這樣的呢?
這就是這一節的重點了 -> flex-shrink <-
同樣的,三個容器處於flex環境中,所以布局之前,父容器還是會計算剩余空間。 這一次計算的結果是這樣的:剩余空間=500px - 300px - 160px - 120px = -80px,剩余空間是一個負數所以很容易理解第一個問題,即使是設置了flex-grow,但是由於沒有剩余空間,所以B1分配到的空間是0。
由於flex環境的父容器的寬度500px是不會變,所以為了是子容器的寬度和最多為父容器的寬度,那就只有兩個辦法:第一個是使子容器換行,第二個是壓縮子容器使之剛好撐滿父容器的寬度。 因為flex子容器是默認不換行的,所以這里不做討論。而第二種壓縮,實際上就是上面例子表現出來的樣式。現在就遇到了上面第二個問題,這三個的壓縮比例是多少呢,各自需要壓縮的空間是多少呢?
這個時候就需要談談flex-shrink,這個屬性其實就是定義一個子容器的壓縮比例。他的默認值是1,所以上面那個例子,就是三個子容器壓縮的比例是一樣的 1:1:1。 如果此時我們設置B1的壓縮比例是2,那會怎樣呢?
我們可以發現,B1被壓縮的更多了。而B2和B3得到了跟多的空間。那我們怎么得出他們各自的壓縮率呢?我們假設B2 B3的壓縮率是X1,那么B1的壓縮率就是X2了,那就有了如下方程:
X2 = 2 * X1; 500 = 300 * X2 + 160 * X1 + 120 * X1;
通過上面我們就可以解出X1和X2等於多少了,這樣就可以計算出壓縮率和被壓縮了多少空間了。
##總結 通過上面的分析,我們就可以得出這樣幾個結論:
1、剩余空間=父容器空間-子容器1.flex-basis/width - 子容器2.flex-basis/width - …
2、如果父容器空間不夠,就走壓縮flex-shrink,否則走擴張flex-grow;
3、如果你不希望某個容器在任何時候都不被壓縮,那設置flex-shrink:0;
4、如果子容器的的flex-basis設置為0(width也可以,不過flex-basis更符合語義),那么計算剩余空間的時候將不會為子容器預留空間。
5、如果子容器的的flex-basis設置為auto(width也可以,不過flex-basis更符合語義),那么計算剩余空間的時候將會根據子容器內容的多少來預留空間。