總想寫flex,卻一直拖——拖——拖,今天算是寫完了。與以往的文章不同,這篇文章更像是寫給自己看的,所以有些術語不會再解釋,如看不懂,可以先去這篇文章里看看術語
1. display為flex的元素會產生一個flex container,該container在正常流內以block-level的形式存在。
2. display為inline-flex的元素會產生一個flex container,該container在正常流內以inline-level的形式存在。
3. 每個flex container都會為它的內容建立一個flex formatting context,這與block container為它的內容建立一個block formatting context很類似。但是,flex container並不是block container, 諸如:
1) float和clear在flex container裡面無效(也就是flex item即使設置了float和clear也不起作用)
2) vertical-align在flex item上也不起作用
3) flex container的margin不會與它的內容的margin重疊
4) ::first-line和::first-letter偽元素在flex container上不起作用
注意:當元素為絕對定位元素、浮動元素或根元素時,display屬性值的computed value的計算規則參照下表
簡單的說,flex container的每個孩子都是一個flex item,而每個flex item都是一個flex-level box,另外,由於在計算computed value時flex item會發生塊級化,因此每個flex item也是一個block container。而對於沒有html元素包裹的連續文字,會被自動包裹在一個匿名的block container flex item里。
釋1: 塊級化 —— 儘管有的flex item的display屬性值為inline,但是在計算computed value時,也會被設為block。
釋2: block container ——該box只能包含block-level box或是建立一個inline formatting context且只能包含inline-level box
因為為絕對定位元素,所以該flex item會脫離流。效果就如同該flex item的static position box(在計算絕對定位元素位置時,會先假設它的position為static,處於正常流中,然後得出一個static position,再依據這個static position去定位。)為flex container的content box。也就是該flex container裡面只有該flex item的static position box,這個flex container是個匿名的flex container。
例1:
css 代碼: div.parent { display: flex; width: 1000px; height:400px; border: solid 2px rgba(75, 234, 12, 0.7); border-radius: 8px; } div.parent > div { border-radius: 8px; flex: 1 1 auto; color: #fff; text-align: center; line-height: 200px; font-size: 26px; } div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); } div.second-child { width: 400px; height: 200px; background-color: rgb(255, 141, 75); } html 代碼: <div class="parent"> <div class="first-child">first-child</div> <div class="second-child">second-child</div> </div>
效果如下:
例2:為div.first-child加上絕對定位。div.first-child改為:
div.first-child { Width: 200px; height: 200px; background-color: rgb(64, 166, 249); position: absolute; }
選中div.second-child可以看到,它的寬度獨佔1000px。
例3: 如果給絕對定位flex item加上align-self: center,它會處於它所在的flex container的交叉軸的中心位置。修改div.first-child如下:
div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); position: absolute; align-self: center; }
例4:而一旦為絕對定位flex item設置了top/bottom,它就會參照第一個父級定位元素去移動,align-self也就失效了。現在設置div.parent為相對定位元素,修改成:
div.parent { display: flex; Width: 1000px; height:400px; border: solid 2px rgba(75, 234, 12, 0.7); border-radius: 8px; position:relative; }
為div.first-child設置偏移量,修改如下:
div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); position: absolute; align-self: center; left: 50px; top: 50px; }
對比上圖,可以看到交叉軸上div.first-child距離div.parent的上邊緣只有上圖的一半,也就是50px,同時div.first-child距離div.parent的左邊緣也是50px。
相鄰的flex item的margin不會重疊(flex container的margin也不會與flex item的margin重疊)。
margin和padding若設置為百分比,則百分比是基於flex container的inline size(若writing mode是horizontal,則inline size為寬度;若mode是vertical,則inline size 為高度)。
例5:
css代碼: div.parent { display: flex; flex-wrap: wrap; width: 400px; height: auto; background-color: rgba(15, 241, 170, 0.42); border-radius: 8px; margin-top: 50px; } div.parent > div { border-radius: 8px; flex: 1 1 auto; color: #fff; text-align: center; line-height: 200px; font-size: 26px; } div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); margin-top: 50px; margin-bottom: 50px; } div.second-child { width: 400px; height: 200px; background-color: rgb(255, 141, 75); margin-top: 50px; }
html代碼: <div class="parent"> <div class="first-child">first-child</div> <div class="second-child">second-child</div> </div>
可以看到div.parent距離root box的上邊緣有50px,而div.first-child的上邊緣距離div.parent的上邊緣也有50px,他們並沒有重疊。div.first-child及div.second-child的margin-top也沒有重疊。
例6:如果div.parent的display為block,並且div.parent及div.first-child的border寬度均為0,它和div.first-child的margin-top會發生重疊。修改div.parent如下:
div.parent { display: block; width: 400px; height: auto; background-color: rgba(15, 241, 170, 0.42); border-radius: 8px; margin-top: 50px; }
滑鼠定位到div.parent上,可以看到它的margin-top和div.first-child的margin-top確實重疊了。同理,div.first-child與div.second-child的margin-top也重疊了。
Flex item可以設置visibility: collapse,達到摺疊的效果。效果類似於table的行摺疊。
Flex item即使摺疊了,但依然有個隱形的空殼存在,為的是保證flex container的cross size的穩定。如果flex container僅有一個flex line(每條flex line上按main size方向依次擺放flex item,類似於line box),那麼某個flex item摺疊可能會影響flex container 的main size,但是不會影響flex container的cross size。
儘管摺疊的flex item不會被渲染,但依然會出現在dom 樹上。為了計算摺疊的flex item的那個空殼的大小,flex layout會先假設所有item都沒有摺疊(處於dom樹形成的過程中,specified value變computed value),然後在由dom樹形成渲染樹的過程中,會將摺疊的flex item用一個保留了原始的cross size的空殼替換掉。
min-width和min-height有了一個新的初始化值,即auto,表示自動設置的min size。
對於flex item,當min-width或min-height的specified value設置為auto,相應的used value是基於內容來設置的。這個值怎麼定呢?
對於min-width,一般,取主軸上width的specified value與主軸上min-content size(一個box的最小size,該size不會導致overflow)的較小值; 如果主軸上width沒有specified value, 但是有個ratio且交叉軸上width設置了specified value,則根據ratio及交叉軸width的specified value得出一個轉換後的size,再取這個size和主軸上min-content size的較小值;如果既沒有設定主軸width的specified value有沒有ratio,那麼直接取主軸上min-content size。
同理min-height。
通常,automatic minimum size取值合理,但是如果是以下情況,還是為min size設置一個具體的值比較好。1. 當flex item的content是一篇較大的文檔,給min-width或min-height設置成字體相關的值比較好,例如min-width: 12em。使用 automatic minimum size會導致溢出。2. 當flex item有較多的孩子節點時,automatic minimum size的取值需要基於min-content size, 而 layout engine為了找到min-content size需要一一遍歷所有的孩子節點,有損性能。如果直接給min size設置specified value,就不必去找min-content size,了。
注意:ratio表示一個元素的width與height的比例關係,一般通過給padding-top設定百分比來表達一個固定比例。
flex container的內容可以按照一定的方向和順序排列。主要依靠flex container的flex-direction和flex-wrap以及flex item的order。
但是有點需切記,不可依靠flex-direction/flex-wrap 的-reverse值 以及order來代替flex item的原本順序,會影響頁面的可訪問性。
Name: flex-directionValue: row | row-reverse | column | column-reverseInitial: rowApplies to: flex containersInherited: no
Name: flex-direction
Name: flex-wrapValue: nowrap | wrap | wrap-reverseInitial: nowrapApplies to: flex containersInherited: no
Name: flex-wrap
flex: nowrap表示flex container為單行,內容大小超出則調整flex item的大小以免溢出
flex: wrap 表示在內容過多時flex container會換行
flex: wrap-reverse 表示在內容過多時flex container會換行,但cross-start及cross-end方向調換。
Name: orderValue: <integer>Initial: 0Applies to: flex itemsInherited: no
Name: order
order可以設置flex item的位置。 這些flex item會在文檔順序的基礎上再基於order屬性值進行再排序,然後按照再排序的結果渲染出來。如果某些flex item的order值相同,則按照它們在文檔里的順序渲染。
例7:
css代碼: div.parent { display: flex; width: 400px; height: auto; border: solid 2px rgba(15, 241, 170, 0.42); border-radius: 8px; } div.parent > div { border-radius: 8px; flex: 1 1 auto; color: #fff; text-align: center; line-height: 200px; font-size: 26px; } div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); } div.second-child { width: 400px; height: 200px; background-color: rgb(255, 141, 75); order: -1; }
當一個flex line還有多餘的空間可擴展,這些空間如何分配給該行的flex item呢?用flex-grow, 它用來設置某個flex item可擴展多少比例的多餘空間。取值為number,默認為0。
當一個flex line的空間不足,這些缺失的空間如何分擔給該行的flex item呢?用flex-shrink,它表示某個flex item需要縮小多少比例的空間,取值為number,默認為1。
定義了分配多餘空間(可為正數亦可為負數)前該flex item所佔的main size,瀏覽器會根據該值來計算主軸上的多餘空間。可設定如下屬性值:
auto: 當specified value為auto時,按如下步驟取值。 第一步:採用的used value為flex item的main size(即主軸上的width或height的屬性值), 第二步:如果這個used value依然為auto,那麼used value 會基於 flex item的content 得到一個具體值。
content: 基於flex item的content得到一個automatic size。
<width>: 和width或height的設置方式一樣,可設為<length> 或 <percentage>
默認值為auto。當主軸為水平方向,設置了flex-basic,則flex item的width值會失效。例如,如果某個flex item的flex-basic設為0,則把該flex item的寬度視為0,即使它本身width為100px,這個100px也會被納入多餘空間中,供flex inline的所有flex item一起分配。
flex屬性為flex-grow flex-shrink flex-basic的縮寫,默認值為0 1 auto,可設定的值為:
initial: 0 1 auto,當有多餘空間時,沒有彈性;當空間不足時,flex item可以縮小。
auto: 1 1 auto,flex會有充足的彈性
none: 0 0 auto, flex會完全沒有彈性
<positive-number>: <positive-number> 1 auto
<flex-grow> <flex-shrink> <flex-basic>: 若flex-grow省略了,默認值取1;若flex-shrink省略了,默認值取1;若flex-basic省略了,默認值取0。
通常,flex item不會縮小到比min content sizes還要小。為防萬一,我們可以為flex item設置min-width或min-height。
a) 如果設置了flex-grow,auto margin 會被設置為0;若設置了flex-basis,沒有設置flex-grow,那麼在主軸方向上,根據flex-basis計算出的多餘的空間都會分配給auto margin)
b) auto margin的優先順序高於justify-content及align-self,軸上任何多餘的空間(不包括負的空間)都會分配給auto margin。
c) 如果box在某個軸上發生溢出了,則auto margin會被忽略,且box在該軸的尾部溢出。(如果既有auto margin, 又有justify-content/align-self/align-items,依然是忽略justify-content/align-self/align-items,採用auto margin,只不過此時因為overflow,接著會忽略auto margin, 在軸的尾部溢出)
總的來說,當存在auto margin時,又有多餘的空間(不包括負的空間),則優先順序如下:
flex-grow > auto margin > justify-content/align-self/align-items
如果box在軸上只剩下負的空間(即溢出),則auto margin被忽略。
例8:
css代碼: div.parent { display: flex; flex-wrap: nowrap; justify-content: center; width: 1000px; height: auto; border: solid 5px rgba(15, 241, 170, 0.42); border-radius: 8px; } div.parent > div { border-radius: 8px; flex: 1 1 auto; color: #fff; text-align: center; line-height: 200px; font-size: 26px; } div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); margin-left: auto; } div.second-child { width: 400px; height: 200px; background-color: rgb(255, 141, 75); }
現在div.parent的justify-content設為center, div.first-child及div.second-child設置了flex: 1 1 auto(其中flex-grow: 1, flex-shrink: 1, flex-basis: auto); 同時div.first-child設置了margin-left為auto,效果如下:
可以看到div.first-child及div.second-child均擴展了,justify-content及auto margin沒起作用。
例9:現在設置div.first-child及div.second-child的flex為0 1 auto,修改如下:
div.parent > div { border-radius: 8px; flex: 0 1 auto; color: #fff; text-align: center; line-height: 200px; font-size: 26px; }
可以看到,剩餘空間都被div.first-child的auto margin-left 佔據了。
例10:現在去掉div.first的auto margin,修改如下:
div.first-child { width: 200px; height: 200px; background-color: rgb(64, 166, 249); }
現在,justify-content起作用了。
justify-content用來設置flex-item在主軸上的對齊方式。
Name: justify-contentValue: flex-start | flex-end | center | space-between | space-aroundInitial: flex-startApplies to: flex containersInherited: no
Name: justify-content
align-items定義了flex container中flex-item在交叉軸上的對齊方式,有點類似justify-content,是針對所有flex item。
align-self定義了某個flex item在交叉軸上的對齊方式,會覆蓋align-items的值。
Name: align-itemsValue: flex-start | flex-end | center | baseline | stretchInitial: stretchApplies to: flex containersInherited: no
Name: align-items
Name: align-selfValue: auto | flex-start | flex-end | center | baseline | stretchInitial: autoApplies to: flex itemsInherited: no
Name: align-self
auto: 對於flex-item,可以設置align-self為auto, auto值的computed value會設置為flex container的align-items的值。
center: flex item的margin box 在交叉軸方向上處於flex line的中間位置。如果flex line的高度比flex item的還要低,則flex item在交叉軸的首尾兩端溢出相等部分。
baseline: flex item會依照flex line的baseline對齊。在交叉軸方向上,baseline與flex item的margin box的上邊緣距離最遠的那個flex item會被放置在交叉軸的開始位置。
stretch: 若flex item的 cross size的computed value為auto(如果flex-direction為row,那麼cross size就是flex item的height),且交叉軸方向的margin均不為auto,那麼align-items/align-self為stretch時,flex item會被拉伸。flex item的cross size的used value會儘可能的接近flex line的高度,如果flex item設置了min(max)-width(height),那麼這個used value會受它們的限制。
其他屬性值直接看下面的效果圖
Name: align-contentValue: flex-start | flex-end | center | space-between | space-around | stretchInitial: stretchApplies to: multi-line flex containersInherited: no
Name: align-content
align-content定義了flex line在flex container的交叉軸方向上的對齊方式,類似於justify-content,都屬於flex container屬性。只不過它要對齊的對象是flex line,且在交叉軸方向,而justify-content要對齊的對象是flex item,在主軸上。
屬性值如下:
space-around: flex container中的flex line之間的空間相等,第一個flex line與 flex container的margin box的上邊緣之間的空間只有flex line之間的空間的一半。
註明:本篇文章中少數圖片來源網路,如有侵權,請立即聯繫本人刪除。
TAG:CSS布局 | Layout | CSS |