天天看點

Flex實作常見布局的彙總

Flex實作常見布局的彙總

flex全稱Flexible Box模型,顧名思義就是靈活的盒子,不過一般都叫彈性盒子,所有PC端及手機端現代浏覽器都支援,是以不用擔心它的相容性,有了這玩意,媽媽再也不用擔心我們的布局。

先簡單介紹一下,要使用flex布局,需要先給一個容器元素設定display:flex讓它變成flex容器。

然後其所有的直接子元素就變成flex子元素了,在flex裡存在兩根軸,叫主軸和交叉軸,互相垂直,主軸預設水準,flex子元素預設會沿主軸排列,可以控制flex子元素在主軸上伸縮,主軸方向可以設定,相關的css屬性分為兩類,一類是給flex容器設定的,一類是給flex子元素設定的,本文在介紹一些典型場景實作的同時也會順帶講解部分屬性,當然更詳細的内容可以閱讀MDN上的教程。

單列布局

單列布局是最簡單的布局了,從上到下排列,如圖:

Flex實作常見布局的彙總

可以使用三個div來表示頭、内容和尾,然後把外層容器,即body設為flex容器,因為flex預設的主軸是水準的,我們需要把它設定為垂直的,然後再設定元素在交叉軸居中即可:

Flex實作常見布局的彙總

當然更常見的情況是内容高度不确定,這樣我們往往會希望在内容高度不滿一屏時底部内容挨着底邊,超過一屏時跟在最後,這首先需要容器元素有固定的高度,否則何來底邊,我們可以把html和body的高度都設為100%,然後去掉給content元素設定的高度,并給它添加一個帶高度的子元素:

Flex實作常見布局的彙總

接下來需要使用到flex-grow屬性,這個是flex子元素上的屬性,用來控制容器還有空間剩餘時,flex子元素怎麼進行擴充,預設值是0,也就是不擴充,子元素會顯示為它們預設的大小,這個所謂的預設大小分幾種情況:

1、如果子元素的另一個屬性flex-basis設定了不為auto的具體數值,那麼無論元素有沒有設定具體大小都顯示為該屬性定義的尺寸;

2、如果子元素的flex-basis的值為auto(預設值),那麼如果元素設定了具體的大小那麼顯示為該設定的尺寸;

3、否則取決于元素内容的max-content大小;

當flex-grow設為一個正數時,那麼各個子元素會按設定的份數來按比例配置設定剩餘可用的空間,比如剩餘空間為90px,三個子元素該屬性值都設為1,那麼每個元素将在原來大小的基礎上加上90/3=30px。

根據上述原理,我們隻需要給content元素的flex-grow屬性設為1即可,其他都是0,是以剩餘空間将全給content元素:

Flex實作常見布局的彙總

這樣内容不足時底部就可以挨着底邊了,但是當内容過多,超過一屏時:

Flex實作常見布局的彙總

可以看到頭和尾都沒了,這是因為flex-shrink的原因,這個也是flex子元素上的屬性,用來控制當子元素的尺寸之和已經超過容器了要怎麼收縮元素,預設值為1,就是按比例減去要收縮的空間,理論上是這樣,但實際上并沒有這麼簡單,接下來簡單測試一下:

容器元素body為800px高,上中下高度分别為100+1000+100=1200px,根據1:1:1的flex-shrink計算總權重為1*100+1*1000+1*100=1200,子元素總高度超過容器400px,這多出的要按的比例從各自高度中減去,具體為:

(400*1*100)/1200=33.33px
(400*1*1000)/1200=333.33px
(400*1*100)/1200=33.33px      

也就是分别都減去上述值,減完後理論上各自的高度變成了66.67px、666.67.67px、66.67px,但是實際上:

Flex實作常見布局的彙總

可以看到頭和尾都變成了0,内容高度沒有變,這是為啥呢?上面我們提到了max-content,同樣,這裡對應着min-content的概念,雖然正常來說應該變成我們計算出的尺寸才對,但是減少到元素内容的min-content後它就不會再變小了。

content元素有個高度為1000的子元素,這個高度就是它的min-content,是以它不會縮小,它一個元素就比容器元素高了,再加上頭和尾因為都沒有内容,是以雖然理論上它們不是為0的。

但是為了更好的顯示效果,浏覽器就直接把它們減少到0了,我們可以随便給頭和尾加一點文字,文字的高度就會變成它們的min-content,它們的高度也就不會變成0:

Flex實作常見布局的彙總

是以這就意味着不要想着去精确計算,把它交給浏覽器,浏覽器會給你以最好的方式呈現。

那麼解決頭和尾不要消失的問題很簡單,可以給它們也加個固定高度的子元素,但是最簡單的方法是把它們的flex-shrink設為0,也就是不收縮:

Flex實作常見布局的彙總

這樣就實作我們的需求了。

經典導航欄

Flex實作常見布局的彙總

如圖所示是一個經典的網站導航欄的布局,logo和導航在左,使用者資訊在右,不用flex可能會使用浮動,上圖使用浮動還好,但是如果右邊是兩個塊,那麼右邊浮動的元素的顯示順序和書寫順序要不一緻才行,或者再用一個元素包裹一下,使用flex則沒有這種煩惱。

該場景可以使用一個容器來包裹左邊的logo和導航,再設定justify-content:space-between來實作,但是有個小技巧可以不用這個包裹元素,就是利用margin的auto值。

回憶一下我們以前水準居中都是怎麼做的,是不是這樣margin:0 auto,margin-left和margin-right的預設值是0,如果設定為auto,将會根據剩餘可用空間來計算,這也是為什麼能水準居中。

因為左右都想盡量多,那麼就隻能平分了,對于本示例,我們隻給使用者名flex子元素設定margin-left:auto,那麼剩餘空間将全部給它,也就相當于把使用者塊擠到右邊去了:

Flex實作常見布局的彙總

隔行交叉顯示

Flex實作常見布局的彙總

有時候為了不讓布局太單調,即使一個清單是同類資料,展示上也會做成上述隔行交叉的樣式,這個使用flex可以輕松的做到,給2n的行設定flex-direction: row-reverse即可讓偶數行的主軸方向由預設的從左向右變成從右向左:

Flex實作常見布局的彙總

此外也可以使用order屬性,這個屬性可以讓flex子元素按order的數值大小來排序顯示,我們可以預設左邊的設為2,右邊的設為3,然後在偶數行再給右邊的設為1,自然就跑到前面去了:

Flex實作常見布局的彙總

網格布局

此網格非grid布局,雖然網格清單用grid是最好的,但是本文的主角是flex,假設我們要實作下面這樣一個清單:

Flex實作常見布局的彙總

上述清單對flex來說是不擅長的,因為要帶間距,是以不能簡單的把子元素寬度設為25%,否則再加上外邊距,一行肯定顯示不下四個,那你可能會想,那我寬度就少一點好了,比如設為20%,然後允許擴充,即flex-grow:1,那樣不就可以把減去子元素寬度及外邊距還剩下的空間再還給子元素了嗎,試試看:

Flex實作常見布局的彙總

可以看到前面一切正常,但是最後一行因為隻有一個元素,且設定了允許擴充,是以它被拉滿整行了,這種效果顯然不是我們要的。

其實我們可以使用内邊距來做間距,設定一下子元素的box-sizing:border-box,讓内邊距包含在寬度内,這樣就可以放心的把子元素的寬度設為25%了,當然這樣的缺點是裡面得再嵌套一個元素用來作為實際的内容容器。

Flex實作常見布局的彙總

聖杯布局

Flex實作常見布局的彙總

所謂聖杯布局如上所示,頭尾高度固定,寬度占滿,中間的内容部分分為三列,兩側寬度固定,高度占滿,中間的内容部分随着浏覽器寬度變化,其實就是我們上面講過的【單列布局】的中間部分變成三列而已,實作完全沒有啥特别的,以【單列布局】為基礎,給content添加三個子元素,兩側定寬,并且不允許收縮,中間允許擴充即可:

Flex實作常見布局的彙總

垂直居中

不知道各位最開始用flex是為什麼,反正筆者就是沖着垂直居中去的,用它實在是太簡單了,之前還考慮是不是定高呀,用什麼定位呀,用flex就是兩步,一讓父元素變成彈性盒子,二設定交叉軸的元素排布方式為居中就完事了:

Flex實作常見布局的彙總

如果還需要水準居中的話就再給容器元素設定主軸的排列方式為justify-content:center,現在連讓文字居中我都是用flex,無情的抛棄了text-align和line-height。

高度自動對齊

有些時候同一列的元素為了美觀我們希望他們的高度是一樣的,如果内容固定不變當然可以直接寫死高度,但如果可變的話就不能寫死了:

Flex實作常見布局的彙總

這個場景使用flex完全不需要額外設定什麼屬性,隻要給容器元素設定display:flex即可,因為flex容器有個屬性align-items,用來設定flex子元素在交叉軸上如何對齊,預設值為stretch,即如果flex子元素未設定高度,那麼将占滿整個容器的高度,因為我們并沒有給容器設定高度,是以容器的高度就是所有flex子元素裡最大的高度。

Flex實作常見布局的彙總

小結

本文以标題黨的名義總結了部分常見布局使用flex的實作,要靈活使用flex還是需要了解它的一些屬性的意義,此外也需要知道flex的邊界在哪,哪些是它不擅長的。

本文總結的難免會有不全,或者有更好的實作,歡迎讨論。

學習更多技能

請點選下方公衆号