1. 程式人生 > >flex佈局異常(flex-grow:1)

flex佈局異常(flex-grow:1)

用flex佈局免去了清浮動的種種,但偶爾遇到異常情況:

當用flex佈局,給了一部分定值,而另一部分鋪滿flex-grow:1;給定值的部分會變化。

這時候flex-basis (default:auto)就出場了,加上flex-basis:0;就不會異常了。

看到一篇更詳細和準確的文章:

轉自: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更符合語義),那麼計算剩餘空間的時候將會根據子容器內容的多少來預留空間。