想必大部分做頂部導航欄(position: fixed;)的都遇見過導航欄遮住鏈接鏈接對象部分內容這種情況吧,如下圖所示,我的頂部導航欄的高度為9vh,video元素是“本店快遞流程”(錨鏈接)跳轉的元素 當我點擊該鏈接時,video元素被遮去了9vh的高度,這是為什麼呢? 我查看了一下源代碼(vi ...
目錄
flex是什麼
根據規範中的描述可知道,Flexbox 模塊提供了一個有效的佈局方式,即使不知道視窗大小或者未知元素情況之下都可以智能的,靈活的調整和分配元素和空間兩者之關的關係。簡單的理解,就是可以自動調整,計算元素在容器空間中的大小。
flex分為兩個部分,即容器(Container)和項目(item)。一旦將一個元素設置為 flex container,那麼其子元素預設全部變為flex item。然後我們就可以通過在 container 設置一些屬性來控制其 item 的佈局。當然,item 自身也有一些 flex 屬性,是只針對自己的屬性。
要將一個元素設置為容器,只要在其 css 里添加 display:flex 或者 display:flex-inline 即可
在介紹 flex 的屬性前,還有一些基本概念需要介紹,這裡就借用網上的一幅圖來說明
如圖,其實已經很清晰明瞭了,容器內有兩條軸,分別叫主軸(main axis)和交叉軸(cross axis),一般情況下 item 沿主軸方向排列,flex預設主軸為橫向,交叉軸為縱向。還有 main start、main end、cross start、cross end 這四個分別表示主軸和交叉軸的起始位置和結束位置。
容器的屬性
容器有六個屬性,flex-direction、flex-wrap、flex-flow、justify-content、align-items、align-content。
- flex-direction
flex-direction 有四個值:row、column、row-reverse、column-reverse。這個屬性用於設置主軸方向。row 為預設值,表示主軸為橫軸,方向從左到右;column 表示主軸為縱軸,方向從上到下;後兩個分別表示從右到左和從下到上的主軸。 - flex-wrap
flex-wrap 有三個值:nowrap、wrap、wrap-reverse。這個屬性設置如何換行。nowrap(預設)表示不換行,此時若主軸方向item總長度超過容器長度,則壓縮 item 主軸方向長度。wrap 表示換行,當 item 總長度超過容器長度時就換行。wrap-reverse 表示反向換行,換行後最靠近 cross end 的為第一行、然後是第二行...... - flex-flow
flex-flow 為前面兩個的簡寫版本,即可以同時在此屬性里設置前面兩個屬性的值,如:flex-flow: nowrap row; - justify-content
justify-content 有五個值:flex-start、flex-end、center、space-between、space-around。此屬性用於調整主軸方向上 item 的對齊方式。flex-start 和 flex-end 分別表示向 main start 和 main end 對齊;center 為主軸方向上的居中對齊;space-between 表示同時向 main start 和 main end 對齊,即兩端對齊,並且兩個 item 之間主軸方向上的間距相等;space-around 表示每個項目兩側之間的距離相等 - align-items
align-items 有五個值:flex-start、flex-end、center、stretch、baseline。此屬性用於調整交叉軸方向上項目的對齊方式。前面三個值和 justify-content 對應的值效果是一樣的,只是方向換成了交叉軸。stretch 為預設值,當 item 交叉軸方向的長度沒有設置或為auto時就會在交叉軸方向填滿容器。baseline 則表示文字對齊,即以 item 中的第一行文字為基準對齊 - align-content
align-content 有六個值:flex-start、flex-end、center、space-around、space-between、stretch。此屬性定義了多根軸線的對齊方式,當只有一根軸線時此屬性無效。此屬性主要針對交叉軸方向,其值在上面都有提到,這裡就不贅述了
item 的屬性
item 有六個屬性:order、flex-grow、flex-shrink、flex-basis、flex、align-self
- order。order 設置同一容器里沿主軸方向的排列順序。可以利用此屬性做交換的動畫
- flex-grow。此屬性設置該 item 在主軸方向有剩餘空間時的放大比例,預設為0,即不放大。註意:這裡的放大計算原理是先計算主軸上的剩餘空間 rest_space,然後計算這條軸上所有 item 的 flex-grow 之和 grow_sum,最後給每個項目 item[i] 的主軸長度增加 rest_space * ( grow[i] / grow_sum )。即先計算出該 item 放大比例占所有 item 放大比例的百分比,然後該 item 增加 該百分比乘以主軸剩餘長度。需要註意的是,當主軸方向沒有剩餘空間時,該屬性無效
- flex-shrink。此屬性和 flex-grow 正好相反,此屬性設置該 item 在主軸方向沒有剩餘空間時的縮小比例,預設值為1,即空間不足時縮小。如果設置為0,則空間不足時會超出容器。我原本以為計算原理和 flex-grow基本相同,後來發現有一點不對。經過網上查詢資料發現,flex- shrink 的計算公式略有區別。flex-shrink 首先要計算權重 TW = E(basis[i] * shrink[i])。也就是所有 item 的 basis * shrink 之和。然後每個 item 的實際長度為 basis[i] - [ (basis[i] * shrink[i] ) / TW ] * need_space。其中,basis 為項目設置長度(見下麵的4),shrink 為縮放值,need_space 為需要所有 item 減少的總長度。需要註意的是:flex-shrink 為0的 item 是不會縮放的,通常這會導致 item 超出容器。
- flex-basis。此屬性指示在分配多餘空間前 item 占的長度,預設情況下為 auto,即設置的width。需要註意的是,如果沒有多餘空間的話,會按照上面第3條的規則縮放;是否有多餘空間是根據主軸上所有 item 的flex-basis 之和來計算的,不是按照 width 來計算的!
- flex。此屬性為 flex-grow、flex-shrink、flex-basis 三個屬性的簡寫,有兩個快捷值:auto( 1 1 auto) 和 none( 0 0 auto )。
- align-self。此屬性可取六個值:flex-start、flex-end、center、baseline、stretch、auto。此屬性設置單獨的排列行為。此屬性的值的含義前面容器屬性部分都有提到,此處不贅述。
一些疑惑和解答
在學習flex的時候,不自覺產生了一些使用方面的疑惑,下麵就是我的一些疑惑和結果
- justify-content 是針對主軸方向的排列,一開始想當然認為是多個 item 的情況,後面突然想起,如果是一個 item 的話,其排序規則又是怎樣的呢?
首先 flex-start、flex-end 和 center 還比較好理解,只有一個項目的時候會貼著 main start、main end 或者在 main start 和 main end 的中間。那麼其值為 space-between 和 space-around的時候呢。前者表示兩端對齊,後者表示等間距對齊,在只有一個項目的情況下會怎麼出現什麼結果呢?結果如下
左邊表示 space-around 的結果,右邊表示 space-between 的結果。可以看出,由於 space-around 要求項目兩側的距離相等,因此只有一個項目時左右距離各占一半,和center的效果是一致的;而 space-between在只有一個項目不能同時對齊左右端的情況下,選擇了左對齊。
結論:當只有一個項目時,space-around 的效果等同於 center,space-between 的效果等同於 flex-start - align-items值為 stretch 時,假如 item 在交叉軸方向的長度沒有設置,並且在交叉軸方向不止一個 item (即在主軸方向有換行),這時會出現什麼結果呢?
這個問題的結果非常有趣,我原以為只要交叉軸方向上只有一個 item 的會直接填滿整個容器,而有兩個 item 的就平分容器。然後結果卻如下圖
原因大概是因為 stretch 的拉伸針對的是整個軸,而上圖是雙軸線,實際上 stretch 的效果是正確的
結論:只要交叉軸方向有大於2個 item,即使交叉軸方向只有一個 item,這個 item 依然不會充滿容器,而是和主軸方向上的 item 長度一致 - align-items值為 baseline 時,若 item 沒有文字會出現什麼結果?
這個問題的結果也很有趣,直接上結果
可以看出,沒有文字的 item 可以認為是文字在最底部的 item
結論:沒有文字的 item 可以認為是文字在最底部的 item - align-content 說明為單軸線時無效,那麼什麼時候為單軸線,什麼時候為多軸線?
經過我的實驗,所謂的單軸線應該就是說沒有換行的情況下,只有一行有 item ,此時 align-content 無效。那麼由此反推,交叉軸方向上 item 的最大個數即主軸數,主軸方向上 item 的最大個數即交叉軸數。如下圖,這就是雙軸線
- justify-content、align-items 和 align-content 似乎差不多?
首先就他們可以取的值而言, align-content 似乎是 align-items 和 justify-content 的大雜燴,後面兩個屬性可以取得值 align-content 都可以取,更為巧合的是,取 align-items 的 align 和 justify-content 的 content 就組成了 align-content,這倒是挺有趣的。
但是三者之間還是區別比較明顯的。justify-content 就不說了,它的區別最明顯,它是針對主軸的,而其他兩個是針對交叉軸的。那麼同樣針對交叉軸的 align-content 和 align-items 有什麼區別呢?
首先看看定義,align-content 相較於 align-items 有一個明顯的不同,那就是它不支持單軸線的操作。下圖是單軸線情況下 align-items 和 align-content 的區別
可以看出,單軸線情況下 align-content 根本沒起作用,而此時 align-items 就起到了非常關鍵的作用。接下來再看看多軸線情況下會發生什麼
於是兩者之間的區別已經躍然紙上了。首先,align-content 單軸線無效,而 align-items 單軸線和多軸線都有效(但多線軸情況下其本質還是對單線軸的設置)。當兩者同時使用且發生衝突時,align-content 的優先順序別更高,也就是說,衝突時 align-content 的操作會覆蓋掉 align-items 的操作
結論:
- justify-content 是針對主軸的,而 align-content 和 align-items 是針對交叉軸的
- align-content 不支持單軸線,align-items 本質就是對每條軸線的操作
- 操作衝突時,align-items 的操作會被 align-content 覆蓋掉