Flex 布局目前已經非常流行了,現在幾乎已經兼容所有瀏覽器了,在文章開始之前我們需要思考一個問題:我們為什么要使用 Flex 布局?
其實答案很簡單,那就是 Flex 布局好用,一個新事物的出現往往是因為舊事物不那么好用了,比如,如果想讓你用傳統的 css 布局來實作一個塊元素垂直水平居中你會怎么做?實作水平居中很簡單,margin: 0 auto就行,而實作垂直水平居中則可以使用定位實作:
<div >
<div ></div>
</div>
.container {
position: relative;
width: 300px;
height: 300px;
background: red;
}
.item {
position: absolute;
background: black;
width: 50px;
height: 50px;
margin: auto;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
或者
.item {
position: absolute;
background: black;
width: 50px;
height: 50px;
margin: auto;
left: calc(50% - 25px);
top: calc(50% - 25px);
}
但是這樣都顯得特別繁瑣,明明可以一個屬性就能解決的事情沒必要寫這么麻煩,而使用 Flex 則可以使用 place-content 屬性簡單的實作(place-content 為 justify-content 和 align-content 簡寫屬性)
.container {
width: 300px;
height: 300px;
background: red;
display: flex;
place-content: center;
}
.item {
background: black;
width: 50px;
height: 50px;
}
接下來的本篇文章將會帶領大家一起來探討Flex布局
基本概念
我們先寫一段代碼作為示例(部分屬性省略)
html
<div >
<div >flex專案</div>
<div >flex專案</div>
<div >flex專案</div>
<div >flex專案</div>
</div>
.container {
display: flex;
width: 800px;
gap: 10px;
}
.item {
color: #fff;
}
flex 容器
我們可以將一個元素的 display 屬性設定為 flex,此時這個元素則成為flex 容器比如container元素
flex 專案
flex 容器的子元素稱為flex 專案,比如item元素
軸
flex 布局有兩個軸,主軸和交叉軸,至于哪個是主軸哪個是交叉軸則有flex 容器的flex-direction屬性決定,默認為:flex-direction:row,既橫向為主軸,縱向為交叉軸,
flex-direction還可以設定其它三個屬性,分別為row-reverse,column,column-reverse,
- row-reverse
- column
- column-reverse
從這里我們可以看出 Flex 軸的方向不是固定不變的,它受到flex-direction的影響
不足空間和剩余空間
當 Flex 專案總寬度小于 Flex 容器寬度時就會出現剩余空間
當 Flex 專案總寬度大于 Flex 容器寬度時就會出現不足空間
Flex 專案之間的間距
Flex 專案之間的間距可以直接在 Flex 容器上設定 gap 屬性即可,如
<div >
<div >A</div>
<div >B</div>
<div >C</div>
<div >D</div>
</div>
.container {
display: flex;
width: 500px;
height: 400px;
gap: 10px;
}
.item {
width: 150px;
height: 40px;
}
Flex 屬性
flex屬性是flex-grow,flex-shrink,flex-basis三個屬性的簡寫,下面我們來看下它們分別是什么,
-
flex-basis可以設定 Flex 專案的大小,一般主軸為水平方向的話和 width 決議方式相同,但是它不一定是 Flex 專案最終大小,Flex 專案最終大小受到flex-grow,flex-shrink以及剩余空間等影響,后面文章會告訴大家最終大小的計算方式 -
flex-grow為 Flex 專案的擴展系數,當 Flex 專案總和小于 Flex 容器時就會出現剩余空間,而flex-grow的值則可以決定這個 Flex 專案可以分到多少剩余空間 -
flex-shrink為 Flex 專案的收縮系數,同樣的,當 Flex 專案總和大于 Flex 容器時就會出現不足空間,flex-shrink的值則可以決定這個 Flex 專案需要減去多少不足空間
既然flex屬性是這三個屬性的簡寫,那么flex屬性簡寫方式分別代表什么呢?
flex屬性可以為 1 個值,2 個值,3 個值,接下來我們就分別來看看它們代表什么意思
- 一個值
如果flex屬性只有一個值的話,我們可以看這個值是否帶單位,帶單位那就是flex-basis,不帶就是flex-grow
.item {
flex: 1;
/* 相當于 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
? .item {
flex: 30px;
/* 相當于 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 30px;
}
- 兩個值
當flex屬性有兩個值的話,第一個無單位的值就是flex-grow,第一個無單位的值則是flex-shrink,有單位的就是flex-basis
.item {
flex: 1 2;
/* 相當于 */
flex-grow: 1;
flex-shrink: 2;
flex-basis: 0;
}
? .item {
flex: 30px 2;
/* 相當于 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
- 三個值
當flex屬性有三個值的話,第一個無單位的值就是flex-grow,第一個無單位的值則是flex-shrink,有單位的就是flex-basis
.item {
flex: 1 2 10px;
/* 相當于 */
flex-grow: 1;
flex-shrink: 2;
flex-basis: 10px;
}
? .item {
flex: 30px 2 1;
/* 相當于 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
? .item {
flex: 2 30px 1;
/* 相當于 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
另外,flex 的值還可以為initial,auto,none,
- initial
initial 為默認值,和不設定 flex 屬性的時候表現一樣,既 Flex 專案不會擴展,但會收縮,Flex 專案大小有本身內容決定
? .item {
flex: initial;
/* 相當于 */
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
- auto
當 flex 設定為 auto 時,Flex 專案會根據自身內容確定flex-basis,既會拓展也會收縮
? .item {
flex: auto;
/* 相當于 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
}
- none
none 表示 Flex 專案既不收縮,也不會擴展
? .item {
flex: none;
/* 相當于 */
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
Flex 專案大小的計算
首先看一下 flex-grow 的計算方式
flex-grow
面試中經常問到: 為什么 flex 設定為 1 的時候,Flex 專案就會均分 Flex 容器? 其實 Flex 專案設定為 1 不一定會均分容器(后面會解釋),這里我們先看下均分的情況是如何發生的
同樣的我們先舉個例子
<div >
<div >Xiaoyue</div>
<div >June</div>
<div >Alice</div>
<div >Youhu</div>
<div >Liehuhu</div>
</div>
.container {
display: flex;
width: 800px;
}
.item {
flex: 1;
font-size: 30px;
}
flex 容器總寬度為 800px,flex 專案設定為flex:1,此時頁面上顯示
我們可以看到每個專案的寬度為 800/5=160,下面來解釋一下為什么會均分:
首先
? .item {
flex: 1;
/* 相當于 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
因為flex-basis為 0,所有 Flex 專案擴展系數都是 1,所以它們分到的剩余空間都是一樣的,下面看一下是如何計算出最終專案大小的
這里先給出一個公式:
Flex專案彈性量 = (Flex容器剩余空間/所有flex-grow總和)*當前Flex專案的flex-grow
其中Flex專案彈性量指的是分配給 Flex 專案多少的剩余空間,所以 Flex 專案的最終寬度為
flex-basis+Flex專案彈性量,
根據這個公式,上面的均分也就很好理解了,因為所有的flex-basis為 0,所以剩余空間就是 800px,每個 Flex 專案的彈性量也就是(800/1+1+1+1+1)*1=160,那么最終寬度也就是160+0=160
剛剛說過 flex 設定為 1 時 Flex 專案并不一定會被均分,下面就來介紹一下這種情況,我們修改一下示例中的 html,將第一個 item 中換成一個長單詞
<div >
<div >Xiaoyueyueyue</div>
<div >June</div>
<div >Alice</div>
<div >Youhu</div>
<div >Liehu</div>
</div>
此時會發現 Flex 容器并沒有被均分
因為計算出的靈活性 200px 小于第一個 Flex 專案的min-content(217.16px),此時瀏覽器會采用 Flex 專案的min-content作為最終寬度,而后面的 Flex 專案會在第一個 Flex 專案計算完畢后再進行同樣的計算
我們修改一下 flex,給它設定一個 flex-basis,看下它計算之后的情況
.item {
text-align: center;
flex: 1 100px;
}
因為每個專案的flex-basis都是 100px,Flex 容器剩余空間為800-500=300px,所以彈性量就是(300/5)*1=60px,最終寬度理論應該為100+60=160px,同樣的因為第一個 Flex 專案的min-content為 217.16px,所以第一個 Flex 專案寬度被設定為 217.16px,最終表現和上面一樣
我們再來看一下為什么第 2,3,4,5 個 Flex 專案寬度為什么是 145.71px
當瀏覽器計算完第一個 Flex 專案為 217.16px 后,此時的剩余空間為800-217.16-100*4=182.84,第 2 個 Flex 專案彈性量為(182.84/1+1+1+1)*1=45.71,所以最終寬度為100+45.71=145.71px,同樣的后面的 Flex 專案計算方式是一樣的,但是如果后面再遇到長單詞,假如第五個是長單詞,那么不足空間將會發生變化,瀏覽器會將第五個 Flex 專案寬度計算完畢后再回頭進行一輪計算,具體情況這里不再展開
所以說想要均分 Flex 容器 flex 設定為 1 并不能用在所有場景中,其實當 Flex 專案中有固定寬度元素也會出現這種情況,比如一張圖片等,當然如果你想要解決這個問題其實也很簡單,將 Flex 專案的min-width設定為 0 即可
.item {
flex: 1 100px;
min-width: 0;
}
flex-grow 為小數
flex-grow 的值不僅可以為正整數,還可以為小數,當為小數時也分為兩種情況:所有 Flex 專案的 flex-grow 之和小于等于 1 和大于 1,我們先看小于等于 1 的情況,將例子的改成
<div >
<div >Acc</div>
<div >Bc</div>
<div >C</div>
<div >DDD</div>
<div >E</div>
</div>
.item:nth-of-type(1) {
flex-grow: 0.1;
}
.item:nth-of-type(2) {
flex-grow: 0.2;
}
.item:nth-of-type(3) {
flex-grow: 0.2;
}
.item:nth-of-type(4) {
flex-grow: 0.1;
}
.item:nth-of-type(5) {
flex-grow: 0.1;
}
效果如圖
我們可以發現專案并沒有占滿容器,它的每個專案的彈性量計算方式為
Flex專案彈性量=Flex容器剩余空間*當前Flex專案的flex-grow
相應的每個專案的實際寬度也就是flex-basis+彈性量,首先先不設定 flex-grow,我們可以看到每個專案的 flex-basis 分別為: 51.2 , 33.88 , 20.08 , 68.56 , 16.5
所以我們可以計算出 Flex 容器的剩余空間為800-51.2 -33.88 - 20.08 - 68.56 - 16.5=609.78,這樣我們就可以算出每個專案的實際尺寸為
A: 實際寬度 = 51.2 + 609.78*0.1 = 112.178
B: 實際寬度 = 33.88 + 609.78*0.2 = 155.836
...
下面看下 flex-grow 之和大于 1 的情況,將例子中的 css 改為
.item:nth-of-type(1) {
flex-grow: 0.1;
}
.item:nth-of-type(2) {
flex-grow: 0.2;
}
.item:nth-of-type(3) {
flex-grow: 0.3;
}
.item:nth-of-type(4) {
flex-grow: 0.4;
}
.item:nth-of-type(5) {
flex-grow: 0.5;
}
此時的效果為
可以看出 Flex 專案是占滿容器的,它的計算方式其實和 flex-grow 為正整數時一樣
Flex專案彈性量 = (Flex容器剩余空間/所有flex-grow總和)*當前Flex專案的flex-grow
所以我們可以得出一個結論: Flex 專案的 flex-grow 之和小于 1,Flex 專案不會占滿 Flex 容器
flex-shrink
flex-shrink 其實和 flex-grow 基本一樣,就是擴展變成了收縮,flex-grow 是專案比例增加容器剩余空間,而 flex-shrink 則是比例減去容器不足空間
修改一下我們的例子:
.item {
flex-basis: 200px;
/* 相當于 */
flex-shrink: 1;
flex-grow: 0;
flex-basis: 200px;
}
此時專案的總寬度200*5=1000px已經大于容器總寬度800px,此時計算第一個專案的不足空間就是800-200*5=-200px,第二個專案的不足空間則是800-第一個專案實際寬度-200*4,依次類推
最終計算公式其實和 flex-grow 計算差不多
Flex專案彈性量 = (Flex容器不足空間/所有flex-shrink總和)*當前Flex專案的flex-shrink
只不過,所以上面例子每個專案可以計算出實際寬度為
第一個 Flex 專案: 200+((800-200x5)/5)*1 = 160px
第二個 Flex 專案: 200+((800-160-200x4)/4)*1 = 160px
第三個 Flex 專案: 200+((800-160-160-200x3)/3)*1 = 160px
第四個 Flex 專案: 200+((800-160-160-160-200x2)/2)*1 = 160px
第五個 Flex 專案: 200+((800-160-160-160-160-200x1)/1)*1 = 160px
如果 Flex 專案的min-content大于flex-basis,那么最終的實際寬度將會取該專案的min-content,比如改一下例子,將第一個 Flex 專案改成長單詞
<div >
<div >XiaoyueXiaoyue</div>
<div >June</div>
<div >Alice</div>
<div >Youhu</div>
<div >Liehu</div>
</div>
可以看出瀏覽器最終采用的是第一個 Flex 專案的min-content作為實際寬度,相應的后面 Flex 專案的寬度會等前一個 Flex 專案計算完畢后在進行計算
比如第二個 Flex 專案寬度= 200+((800-228.75-200x4)/4)*1 = 142.81px
flex-shrink 為小數
同樣的 flex-shrink 也會出現小數的情況,也分為 Flex 專案的 flex-shrink 之和小于等于 1 和大于 1 兩種情況,如果大于 1 和上面的計算方式一樣,所以我們只看小于 1 的情況,將我們的例子改為
.item {
flex-basis: 200px;
flex-shrink: 0.1;
}
效果為
此時我們會發現 Flex 專案溢位了容器,所以我們便可以得出一個結論:Flex 專案的 flex-shrink 之和小于 1,Flex 專案會溢位 Flex 容器
下面看一下它的計算公式
Flex專案彈性量=Flex容器不足空間*當前Flex專案的flex-shrink
Flex專案實際寬度=flex-basis + Flex專案彈性量
比如上面例子的每個 Flex 專案計算結果為
第一個 Flex 專案寬度 = 200+(800-200x5)x0.1=180px,但是由于它本身的min-content為 228.75,所以最終寬度為 228.75
第二個 Flex 專案寬度 =200-(800-228.75-200x4)x0.1=117.125
第三個 Flex 專案寬度...
Flex 的對齊方式
Flex 中關于對齊方式的屬性有很多,其主要分為兩種,一是主軸對齊方式:justify-*,二是交叉軸對齊方式:align-*
首先改一下我們的例子,將容器設定為寬高為 500x400 的容器(部分屬性省略)
<div >
<div >A</div>
<div >B</div>
<div >C</div>
</div>
.container {
display: flex;
width: 500px;
height: 400px;
}
.item {
width: 100px;
height: 40px;
}
主軸對齊屬性
這里以橫向為主軸,縱向為交叉軸
justify-content
justify-content的值可以為:
- flex-start 默認值,主軸起點對齊
- flex-end 主軸終點對齊
- left 默認情況下和 flex-start 一致
- right 默認情況下和 flex-end 一致
- center 主軸居中對齊
- space-between 主軸兩端對齊,并且 Flex 專案間距相等
- space-around 專案左右周圍空間相等
- space-evenly 任何兩個專案之間的間距以及邊緣的空間相等
交叉軸對齊方式
align-content
align-content 屬性控制整個 Flex 專案在 Flex 容器中交叉軸的對齊方式
**注意設定 align-content 屬性時候必須將 flex-wrap 設定成 wrap 或者 wrap-reverse,**它可以取得值為
- stretch 默認值,當我們 Flex 元素不設定高度的時候,默認是拉伸的
比如將 Flex 元素寬度去掉
.item {
width: 100px;
}
- flex-start 位于容器開頭,這個和 flex-direction:屬性有關,默認在頂部
- flex-end 位于容器結尾
- center 元素居中對齊
- space-between 交叉軸上下對齊,并且 Flex 專案上下間距相等
此時我們改下例子中 Flex 專案的寬度使其換行,因為如果 Flex 專案只有一行,那么 space-between 與 flex-start 表現一致
.item {
width: 300px;
}
- space-around 專案上下周圍空間相等
- space-evenly 任何兩個專案之間的上下間距以及邊緣的空間相等
align-items
align-items 屬性定義 flex 子項在 flex 容器的當前行的交叉軸方向上的對齊方式,它與 align-content 有相似的地方,它的取值有
-
stretch 默認值,當我們 Flex 元素不設定高度的時候,默認是拉伸的
-
center 元素位于容器的中心,每個當前行在圖中已經框起來
-
flex-start 位于容器開頭
-
flex-end 位于容器結尾
-
baseline 位于容器的基線上
比如給 A 專案一個 padding-top
.item:nth-of-type(1) {
padding-top: 50px;
}
沒設定 baseline 的表現
設定 baseline 之后
通過上面的例子我們可以發現,如果想要整個 Flex 專案垂直對齊,在只有一行的情況下,align-items 和 align-content 設定為 center 都可以做到,但是如果出現多行的情況下 align-items 就不再適用了
align-self
上面都是給 Flex 容器設定的屬性,但是如果想要控制單個 Flex 專案的對齊方式該怎么辦呢?
其實 Flex 布局中已經考慮到了這個問題,于是就有個 align-self 屬性來控制單個 Flex 專案在 Flex 容器側交叉軸的對齊方式,
align-self 和 align-items 屬性值幾乎是一致的,比如我們將整個 Flex 專案設定為 center,第二個 Flex 專案設定為 flex-start
.container {
display: flex;
width: 500px;
height: 400px;
align-items: center;
}
.item {
width: 100px;
height: 40px;
}
.item:nth-of-type(2) {
align-self: flex-start;
}
注意,除了以上提到的屬性的屬性值,還可以設定為 CSS 的關鍵詞如 inherit 、initial 等
交叉軸與主軸簡寫
place-content
place-content 為 justify-content 和 align-content 的簡寫形式,可以取一個值和兩個值,如果設定一個值那么 justify-content 和 align-content 都為這個值,如果是兩個值,第一個值為 align-content,第二個則是 justify-content
到這里關于Flex布局基本已經介紹完了,肯定會有些細枝末節沒有考慮到,這可能就需要我們在平時作業和學習中去發現了
點個贊吧~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/543241.html
標籤:其他
上一篇:記錄--實時音視頻功能簡析(live-pusher與live-player)
下一篇:JavaScript 高階函式
