30分鐘徹底弄懂flex佈局

来源:https://www.cnblogs.com/qcloud1001/archive/2018/10/25/9848619.html
-Advertisement-
Play Games

歡迎大家前往 "騰訊雲+社區" ,獲取更多騰訊海量技術實踐乾貨哦~ 本文由 "elson" 發表於 "雲+社區專欄" 目前在不考慮IE以及低端安卓機(4.3 )的相容下,已經可以放心使用flex進行佈局了。什麼是flex佈局以及它的好處,這裡就不再贅述。 在這篇文章里,想說說flex佈局的屬性語法及 ...


歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~

本文由elson發表於雲+社區專欄

目前在不考慮IE以及低端安卓機(4.3-)的相容下,已經可以放心使用flex進行佈局了。什麼是flex佈局以及它的好處,這裡就不再贅述。

在這篇文章里,想說說flex佈局的屬性語法及其細節。那麼網上也有不少flex佈局的教程,為什麼又要再寫一篇?

首先,flex佈局的迷之屬性們,如果一知半解,機械記憶的話,那不到半個月基本忘光光。先感受一下這12個flex佈局屬性,是不是很“迷”人。

容器屬性

  • flex-flow
  • flex-direction
  • flex-wrap
  • justify-content
  • align-items
  • align-content

元素屬性

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

就連老外也都在twitter吐槽不好理解,可見還是有一定的學習成本。

img

而目前很多flex教程主要以列舉屬性為主,缺乏對比和理解性脈絡。

因此,下麵會通過我梳理的一個脈絡去理解flex佈局,包括不同屬性的異同以及一些容易造成誤解的細節點,徹底弄懂flex佈局。

一、flex彈性盒模型

對於某個元素只要聲明瞭display: flex;,那麼這個元素就成為了彈性容器,具有flex彈性佈局的特性。

img

  1. 每個彈性容器都有兩根軸:主軸和交叉軸,兩軸之間成90度關係。註意:水平的不一定就是主軸。
  2. 每根軸都有起點和終點,這對於元素的對齊非常重要。
  3. 彈性容器中的所有子元素稱為<彈性元素>,彈性元素永遠沿主軸排列
  4. 彈性元素也可以通過display:flex設置為另一個彈性容器,形成嵌套關係。因此一個元素既可以是彈性容器也可以是彈性元素

彈性容器的兩根軸非常重要,所有屬性都是作用於軸的。下麵從軸入手,將所有flex佈局屬性串起來理解。

二、主軸

flex佈局是一種一維佈局模型,一次只能處理一個維度(一行或者一列)上的元素佈局,作為對比的是二維佈局CSS Grid Layout,可以同時處理行和列上的佈局。

也就是說,flex佈局大部分的屬性都是作用於主軸的,在交叉軸上很多時候只能被動地變化

1. 主軸的方向

我們可以在彈性容器上通過flex-direction修改主軸的方向。如果主軸方向修改了,那麼:

  1. 交叉軸就會相應地旋轉90度。
  2. 彈性元素的排列方式也會發生改變,因為彈性元素永遠沿主軸排列

imgflex-direction:row

imgflex-direction:column

imgflex-direction:row-reverse

imgflex-direction:column-reverse

2. 沿主軸的排列處理

彈性元素永遠沿主軸排列,那麼如果主軸排不下,該如何處理?

img

通過設置flex-wrap: nowrap | wrap | wrap-reverse可使得主軸上的元素不折行、折行、反向折行。

預設是nowrap不折行,難道任由元素直接溢出容器嗎?當然不會,那麼這裡就涉及到元素的彈性伸縮應對,下麵會講到。

wrap折行,顧名思義就是另起一行,那麼折行之後行與行之間的間距(對齊)怎樣調整?這裡又涉及到交叉軸上的多行對齊。

wrap-reverse反向折行,是從容器底部開始的折行,但每行元素之間的排列仍保留正向。

img

3. 一個複合屬性

flex-flow = flex-drection + flex-wrap

flex-flow相當於規定了flex佈局的“工作流(flow)”

flex-flow: row nowrap;

三、元素如何彈性伸縮應對

flex-wrap: nowrap;不折行時,容器寬度有剩餘/不夠分,彈性元素們該怎麼“彈性”地伸縮應對?

這裡針對上面兩種場景,引入兩個屬性(需應用在彈性元素上)

  1. flex-shrink:縮小比例(容器寬度<元素總寬度時如何收縮)
  2. flex-grow:放大比例(容器寬度>元素總寬度時如何伸展)

1. flex-shrink: 縮小比例

來看下以下場景,彈性容器#container寬度是200px,一共有三個彈性元素,寬度分別是50px、100px、120px。在不折行的情況下,此時容器寬度是明顯不夠分配的。

實際上,flex-shrink預設為1,也就是當不夠分配時,元素都將等比例縮小,占滿整個寬度,如下圖。

img

#container {
  display: flex;
  flex-wrap: nowrap;
}

元素收縮的計算方法

真的是等比縮小(每個元素各減去70/3的寬度)嗎?這裡稍微深究一下它的收縮計算方法。

  1. 彈性元素1:50px→37.03px
  2. 彈性元素2:100px→74.08px
  3. 彈性元素3:120px→88.89px

先拋結論:flex-shrink: 1並非嚴格等比縮小,它還會考慮彈性元素本身的大小

  • 容器剩餘寬度:-70px
  • 縮小因數的分母:1*50 + 1*100 + 1*120 = 270 (1為各元素flex-shrink的值)
  • 元素1的縮小因數:1*50/270
  • 元素1的縮小寬度為縮小因數乘於容器剩餘寬度:1*50/270 * (-70)
  • 元素1最後則縮小為:50px + (1*50/270 *(-70)) = 37.03px

加入彈性元素本身大小作為計算方法的考慮因素,主要是為了避免將一些本身寬度較小的元素在收縮之後寬度變為0的情況出現。

2. flex-grow: 放大比例

同樣,彈性容器#container寬度是200px,但此時只有兩個彈性元素,寬度分別是50px、100px。此時容器寬度是有剩餘的。

那麼剩餘的寬度該怎樣分配?而flex-grow則決定了要不要分配以及各個分配多少。

(1)在flex佈局中,容器剩餘寬度預設是不進行分配的,也就是所有彈性元素的flex-grow都為0。

img

(2)通過指定flex-grow為大於零的值,實現容器剩餘寬度的分配比例設置。

img

元素放大的計算方法

放大的計算方法並沒有與縮小一樣,將元素大小納入考慮。

僅僅按flex-grow聲明的份數算出每個需分配多少,疊加到原來的尺寸上。

  • 容器剩餘寬度:50px
  • 分成每份:50px / (3+2) = 10px
  • 元素1放大為:50px + 3 * 10 = 80px

無多餘寬度時,flex-grow無效

下圖中,彈性容器的寬度正好等於元素寬度總和,無多餘寬度,此時無論flex-grow是什麼值都不會生效。

img

同理,對於flex-shrink,在容器寬度有剩餘時也是不會生效的。因此這兩個屬性是針對兩種不同場景的互斥屬性。

四、彈性處理與剛性尺寸

在進行彈性處理之餘,其實有些場景我們更希望元素尺寸固定,不需要進行彈性調整。設置元素尺寸除了width和height以外,flex還提供了一個flex-basis屬性。

flex-basis設置的是元素在主軸上的初始尺寸,所謂的初始尺寸就是元素在flex-growflex-shrink生效前的尺寸。

1. 與width/height的區別

首先以width為例進行比較。看下下麵的例子。#container {display:flex;}

<div id="container">
  <div>11111</div>
  <div>22222</div>
</div>

(1) 兩者都為0

img

  • width: 0 —— 完全沒顯示
  • flex-basis: 0 —— 根據內容撐開寬度

(2) 兩者非0

img

  • width: 非0;
  • flex-basis: 非0

—— 數值相同時兩者等效

—— 同時設置,flex-basis優先順序高

(3) flex-basis為auto

img

flex-basis為auto時,如設置了width則元素尺寸由width決定;沒有設置則由內容決定

(4) flex-basis == 主軸上的尺寸 != width

img

  • 將主軸方向改為:上→下
  • 此時主軸上的尺寸是元素的height
  • flex-basis == height

2. 常用的複合屬性 flex

這個屬性應該是最容易迷糊的一個,下麵揭開它的真面目。

flex = flex-grow + flex-shrink + flex-basis

複合屬性,前面說的三個屬性的簡寫。

img

一些簡寫

  • flex: 1 = flex: 1 1 0%
  • flex: 2 = flex: 2 1 0%
  • flex: auto = flex: 1 1 auto;
  • flex: none = flex: 0 0 auto; // 常用於固定尺寸 不伸縮

flex:1 和 flex:auto 的區別

其實可以歸結於flex-basis:0flex-basis:auto的區別。

flex-basis是指定初始尺寸,當設置為0時(絕對彈性元素),此時相當於告訴flex-growflex-shrink在伸縮的時候不需要考慮我的尺寸;相反當設置為auto時(相對彈性元素),此時則需要在伸縮時將元素尺寸納入考慮。

因此從下圖(轉自W3C)可以看到絕對彈性元素如果flex-grow值是一樣的話,那麼他們的尺寸一定是一樣的。

img

五、容器內如何對齊

前面講完了元素大小關係之後,下麵是另外一個重要議題——如何對齊。可以發現上面的所有屬性都是圍繞主軸進行設置的,但在對齊方面則不得不加入作用於交叉軸上。需要註意的是這些對齊屬性都是作用於容器上。

1. 主軸上的對齊方式

justify-content

img

2. 交叉軸上的對齊方式

主軸上比較好理解,重點是交叉軸上。因為交叉軸上存在單行和多行兩種情況。

交叉軸上的單行對齊

align-items

預設值是stretch,當元素沒有設置具體尺寸時會將容器在交叉軸方向撐滿。

align-items不為stretch時,此時除了對齊方式會改變之外,元素在交叉軸方向上的尺寸將由內容或自身尺寸(寬高)決定。

img

img

img

img

img

註意,交叉軸不一定是從上往下,這點再次強調也不為過。

img

交叉軸上的多行對齊

還記得可以通過flex-wrap: wrap使得元素在一行放不下時進行換行。在這種場景下就會在交叉軸上出現多行,多行情況下,flex佈局提供了align-content屬性設置對齊。

align-contentalign-items比較類似,同時也比較容易迷糊。下麵會將兩者對比著來看它們的異同。

首先明確一點:align-content只對多行元素有效,會以多行作為整體進行對齊,容器必須開啟換行。

align-content: stretch | flex-start | flex-end | center | space-between | space-around

align-items: stretch | flex-start | flex-end | center | baseline

在屬性值上,align-contentalign-items多了兩個值:space-betweenspace-around

align-content與align-items異同對比

align-items一樣,align-content:預設值也是stretch。兩者同時都為stretch時,毫無懸念所有元素都是撐滿交叉軸。

#container {
  align-items: stretch;
  align-content: stretch;
}

img

當我們將align-items改為flex-start或者給彈性元素設置一個具體高度,此時效果是行與行之間形成了間距。

#container {
  align-items: flex-start;
  align-content: stretch;
}

/*或者*/
#container {
  align-content: stretch;
}
#container > div {
  height: 30px;
}

為什麼?因為align-content會以整行為單位,此時會將整行進行拉伸占滿交叉軸;而align-items設置了高度或者頂對齊,在不能用高度進行拉伸的情況下,選擇了用間距。

img

嘗試把align-content設置為頂對齊,此時以行為單位,整體高度通過內容撐開。

align-items僅僅管一行,因此在只有第一個元素設置了高度的情況下,第一行的其他元素遵循align-items: stretch也被拉伸到了50px。而第二行則保持高度不變。

#container {
  align-items: stretch;
  align-content: flex-start;
}
#container > div:first-child {
    height: 50px;
}

img

兩者的區別還是不明顯?來看下麵這個例子。

這裡僅對第二個元素的高度進行設置,其他元素高度則仍保持內容撐開。

img

以第一個圖為例,會發現align-content會將所有行進行頂對齊,然後第一行由於第二個元素設置了較高的高度,因此體現出了底對齊。

兩者差異總結:

  • 兩者“作用域”不同
  • align-content管全局(所有行視為整體)
  • align-items管單行

能否更靈活地設置交叉軸對齊

除了在容器上設置交叉軸對齊,還可以通過align-self單獨對某個元素設置交叉軸對齊方式。

  1. 值與align-items相同
  2. 可覆蓋容器的align-items屬性
  3. 預設值為auto,表示繼承父元素的align-items屬性

img

#container {
  display: flex;
  align-items: flex-start;
}

#container > div:first-child {
  align-self: stretch;
}

#container > div:nth-child(3) {
  align-self: center;
}

#container > div:nth-child(4) {
  align-self: flex-end;
}

六、其他

order:更優雅地調整元素順序

img

#container > div:first-child {
  order: 2;
}
#container > div:nth-child(2) {
  order: 4;
}
#container > div:nth-child(3) {
  order: 1;
}
#container > div:nth-child(4) {
  order: 3;
}

order:可設置元素之間的排列順序

  1. 數值越小,越靠前,預設為0
  2. 值相同時,以dom中元素排列為準

七、總結

img

img

img

參考阮老師博文中的骰子練習,我做了張圖,大家不妨可以各自實現下,理解之後應該能夠比較輕鬆地寫出來。codepen

img

參考資料

Flex 佈局教程:語法篇

Flex 佈局教程:實例篇

flex code pen

理解Flexbox:你需要知道的一切

深入理解css3中的flex-grow、flex-shrink、flex-basis

A Complete Guide to Flexbox

flex實戰及坑總結

flex bugs集錦

相關閱讀
bitset用法小結
Numpy基礎知識點彙總
【每日課程推薦】機器學習實戰!快速入門線上廣告業務及CTR相應知識

此文已由作者授權騰訊雲+社區發佈,更多原文請點擊

搜索關註公眾號「雲加社區」,第一時間獲取技術乾貨,關註後回覆1024 送你一份技術課程大禮包!

海量技術實踐經驗,盡在雲加社區


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇針對Surface模塊進行分析,從Java層的Activity創建開始,到ViewRoot、WindowsManagerService,再到JNI層和Native層。 首先推薦一個Android源碼查看的網站:http://androidxref.com/ Surface的創建涉及三個部分: A ...
  • 有些App在點擊下載按鈕的時候,可以在按鈕上顯示進度,我們可以通過繼承原生Button,重寫onDraw來實現帶進度條的按鈕。 Github:https://github.com/imcloudfloating/ProgressBar 1.效果: 2.原理: 創建三個GradientDrawable ...
  • 這次想來講講系統應用集成過程中遇到的一些坑,尤其是 so 文件相關的坑。 背景 埋這些坑的最初來源是由於測試人員在集成新終端設備時提了個 bug: app 在這個設備上無法啟動。 隨後拋來了一份日誌,過濾了下,最重要的其實就一條,crash 日誌: app 使用了 fresco 圖片庫,最初猜想是不 ...
  • 歡迎大家前往 "騰訊雲+社區" ,獲取更多騰訊海量技術實踐乾貨哦~ 本文由 "WeTest質量開放平臺團隊" 發表於 "雲+社區專欄" 作者:陳裕發, 騰訊系統測試工程師 商業轉載請聯繫騰訊WeTest獲得授權,非商業轉載請註明出處。 原文鏈接: " http://wetest.qq.com/lab ...
  • 如果你的項目中有模塊跟二維碼相關的話,那你一定聽過或者用過大名鼎鼎的zxing開源庫。 什麼是zxing? ZXing是一個開源的,用Java實現的多種格式的1D/2D條碼圖像處理庫,它包含了聯繫到其他語言的埠。zxing可以實現使用手機的內置的攝像頭完成條形碼的掃描及解碼。 本篇文章就來學習zx ...
  • 筆者在看了相關的教程之後發現教程當中的資源已經過時了。當我們在創建了一個新的空白的工程之後,會發現其文件夾下麵的分文件夾目錄和官方的教程文件結構完全不同,因此會引起很多誤解。筆者使用的是最新版的Android Stuidio,其目錄結構如下圖所示: 一.創建主活動(First活動) 從中我們可以得到 ...
  • 一,首先,我們在菜單欄上找到這一欄: 然後點擊build,再點擊generate apk,然後出現以下界面: 由於之前我們並沒有進行apk文件的生成,因此需要這個apk key做一個驗證,以防您的app上線之後被別人盜用,同時證明自己對這個app的擁有權。key store path就是您app k ...
  • Android json支持五種數據類型 String / int(float)/bool / null / object 今天說 object : ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...