前言我也不知道怎麼寫,那廢話就不多說了,反正flex佈局不考慮相容性的話用處還是挺多的,個人感覺也是挺神奇挺好用的。在平時的工作中,flex發揮了非常大的作用,今天就來總結一下吧。
語法介紹
這裡只介紹我常用的flex屬性,有不足的地方歡迎指正(以下情況預設都是在瀏覽器的預設屬性基礎上進行介紹)
啟用flex佈局
display: flex;
複製程式碼
這個想必大家都非常熟悉了,我也就不多說了。
佈局方向
flex-direction: row; // 瀏覽器預設佈局方式,在同一行內進行排列(flex-wrap: nowrap的情況下)
flex-direction: column; // 在同一列內進行排列,類似於常規的一行一行的排列
複製程式碼
至於row-reverse
和 column-reverse
就不說了,感覺應用場景不多。
對齊方式
這裡就需要認識一下主軸(main axis)和交叉軸(cross axis)。
簡單地說主軸就是排列方向,交叉軸和排列方向相垂直。
具體地說:flex-direction: row;
時,主軸是指水平方向,交叉軸是垂直方向。flex-direction: column;
時,主軸是指垂直方向,交叉軸是水平方向。
用圖來表示的話就是:
主軸對齊
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
複製程式碼
- flex-start 靠左對齊(row)或是靠上對齊(column)
- flex-end 靠右對齊(row)或是靠下對齊(column)
- center 居中對齊
- space-between 兩邊對齊,專案之間的間隔都相等(常用)
- space-around 兩邊對齊,但跟 space-between 不同的是,它在兩側各有 1/2 的間距(不常用)
- space-evenly 兩邊對齊,兩側各有 1 倍的間距(看的別人的介紹,不知道有什麼實際用途,只知道兩邊的空白比space-around大)
交叉軸對齊
align-items: flex-start | flex-end | center | baseline | stretch;
複製程式碼
- flex-start 靠上對齊(row)或是靠左對齊(column)
- flex-end 靠下對齊(row)或是靠右對齊(column)
- center 居中對齊
- baseline: 專案的第一行文字的基線對齊;
- stretch(預設值)如果專案未設定寬度/高度或設為auto並且
flex-wrap: nowrap;(未設定時預設就是nowrap)
,將佔滿整個容器的高度(row)/寬度(column)
交叉軸和主軸不一樣,可沒有什麼兩端對齊,所以可千萬別混淆了。
單行時使用 align-items, 多行時使用align-content, 這兩種都是使用於display: flex
的元素,而align-self可以單獨設定子元素的交叉軸對齊方式。
是否換行
flex-wrap: nowrap | wrap | wrap-reverse;
複製程式碼
當使用nowrap時,當子元素的寬度之和超過父元素的寬度時並不會換行,而是儘量壓縮自身以保障不超過父元素的寬度,所以有時候你會發現flex內的子元素寬度跟你想象的不一樣就是這個原因造成的。
至於寬度到底是怎麼計算的嘛,說來還是有點複雜的。理論上, 當子元素的寬度之和超過父元素的寬度時,子元素的寬度 = 子元素所設定的寬度 / 子元素之和 父元素的寬度。
假設父元素是100px,子元素A是100px,B是400px,C元素是500px,那麼理論上子元素之和為1000px,A = 100 / 1000 * 100 = 10px,B = 400 / 1000 * 100 = 40px, C = 500 / 1000 * 100 = 50px。
當然了,這只是理論上的理想情況。實際上,能不能按照理論分配,還得看子元素內的實際寬度,什麼是實際寬度呢?就是它裡面的內容所佔的寬度,假設A裡面的文字有3個,佔用了25px,那麼它的最終寬度就是25px,而不是所分配的10px,B和C也會相應的減少。
使用wrap的話就不會存在這個問題了,在一定程度上可以替代之前的inline-block和float的佈局方式。
flex-grow
flex: 1;
/*
其實就相當於
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
*/
複製程式碼
這個屬性的作用就是將剩餘寬度按照比例分配給該子元素。常用於兩欄佈局,一側定寬,另一側設定flex: 1;
即可獲得剩餘寬度。
排列順序order
order: 1; /* 任意正整數 */
複製程式碼
這個東西可是很神奇的了,不需要改變html的結構,直接改變顯示的順序,比如常見的列表介紹,第一行左圖右文字,第二行左文字右圖。
還有一種應用場景就是聊天介面了,這個稍後會講到。
總算是講完基礎部分,接下來終於可以進入今天的正題了。
實戰部分
居中
這個應該是最常遇到的佈局方式了吧,主要分為單行居中,多行居中。
單行居中
其實這裡還分為只有一行的元素水平居中和多行中的某一行水平居中兩種情況,暫時只介紹第一種情況,下一段再介紹後一種情況。
<div class="flex-center" style="background: red;color: #fff;padding: 20px 0;">
單行水平居中
</div>
複製程式碼
.flex-center {
display: flex;
flex-direction: row;
justify-content: center;
}
複製程式碼
排列方向為row的情況設定主軸對齊方式為center即可,沒什麼好說的。
多行居中(換行時)
可以看到在使用flex-wrap: wrap
後,align-content: center
是將所有的子元素組合成一個整體後垂直居中,而align-content: center
則是將剩餘部分的空白平均分配給子元素的上下兩側。所以這種換行後的多行垂直居中推薦大家使用align-content。
<div class="attr-title">align-content: center</div>
<div class="flex box" style="align-content: center;">
<div class="red">red</div>
<div class="green">grren</div>
<div class="blue">blue</div>
</div>
<div class="attr-title">align-items: center</div>
<div class="flex box" style="align-items: center;">
<div class="red">red</div>
<div class="green">grren</div>
<div class="blue">blue</div>
</div>
複製程式碼
.flex {
display: flex;
flex-direction: row;
}
.red {
background: red;
width: 50%;
height: 30px;
}
.green {
background: green;
height: 40px;
width: 100%;
}
.blue {
background: blue;
width: 100%;
}
.attr-title {
margin-top: 24px;
margin-bottom: 12px;
}
.box {
border: 5px solid #ccc;
flex-wrap: wrap;
height: 200px;
}
複製程式碼
多行居中(column)
程式碼如下:
<div class="attr-title">flex-direction: column 垂直居中</div>
<div class="flex-center column border">
<div class="red">red</div>
<div class="green">grren</div>
<div class="blue">blue</div>
</div>
複製程式碼
.flex-center {
display: flex;
flex-direction: row;
justify-content: center;
}
.column {
flex-direction: column;
}
.border {
border: 5px solid #ccc;
height: 200px;
}
複製程式碼
多行垂直居中的話,相比較上面換行的那種,還是推薦大家使用column這種方式。畢竟程式碼簡潔,更好理解。還有很重要的一點就是可以更靈活的控制子元素在水平方向的對齊方式,在文章的排版中應該會比較常見。
可能有的人會說這種排版使用text-align
也能辦到。確實也可以,但是text-align
只能作用於塊級元素,而flex佈局則沒有這個侷限性。
<div class="flex column">
<h2 class="title self-center">黑洞的發現</h2>
<div class="flex between">
<div class="author">某網站</div>
<time class="time self-end">釋出時間:2019-04-12</time>
</div>
<article class="article">
<p>正文中打撒打撒打撒多撒正文中打撒打撒打撒多撒正文中打撒打撒打撒多撒</p>
</article>
</div>
複製程式碼
.flex {
display: flex;
flex-direction: row;
}
.column {
flex-direction: column;
}
.between {
justify-content: space-between;
}
.self-center {
align-self: center;
}
.self-end {
align-self: flex-end;
}
.author {
font-size: 14px;
color: #666;
}
.time {
color: #999;
font-size: 12px;
}
.article p {
text-indent: 2em;
line-height: 1.6;
}
複製程式碼
兩端對齊
這個應用場景也挺多的,比如左側是標題,右側是更多>>。原理也很簡單,就是
.flex {
display: flex;
flex-direction: row;
}
.between {
justify-content: space-between;
}
複製程式碼
在需要兩端對齊的時候,只需要在父元素加上這兩個類名就可以了。效果圖就不上了,上方文章排版的那個就用到了。
多欄佈局
這裡只舉例最簡單的兩欄佈局,其他的類似,自己推導即可。
在應用flex以後,左側定寬,右側flex: 1;
即可獲得剩餘寬度。
<div class="flex">
<div class="red">red</div>
<div class="green">grren</div>
</div>
複製程式碼
.flex {
display: flex;
flex-direction: row;
}
.red {
width: 100px;
background: red;
height: 36px;
}
.green {
flex: 1;
background: green;
}
複製程式碼
不知道大家有沒有發現,上圖中我只設定了red的高度,但是green的高度居然和red的一致!平時的佈局中不是隻有文字的高度嗎?
其實這就是上文所說的自動填充高度了,align-items: stretch
會將未主動設定高度的子元素拉伸至與高度最高的子元素相同。align-items的預設值就是stretch,所以如果不需要自動填充高度,你需要設定align-items為flex-start,flex-end,center等其他的值。
order簡單運用
有了order以後,就可以在不改變html結構的情況下,通過改變order的數值來改變子元素的顯示順序。
分析一下這個佈局,其實也就是兩欄佈局,然後文字部分垂直居中,前面都介紹過了,所以實現起來是很簡單的。
程式碼如下:
<ul class="list">
<li class="flex item even">
<img src="https://taidaxin.oss-cn-qingdao.aliyuncs.com/1.jpg" alt="" class="img">
<div class="content flex-center column">
<div class="p">介紹</div>
<div class="p">flex佈局</div>
</div>
</li>
<li class="flex item odd">
<img src="https://taidaxin.oss-cn-qingdao.aliyuncs.com/1.jpg" alt="" class="img">
<div class="content flex-center column">
<div class="p">介紹</div>
<div class="p">flex佈局</div>
</div>
</li>
</ul>
複製程式碼
.flex {
display: flex;
flex-direction: row;
}
.flex-center {
display: flex;
flex-direction: row;
justify-content: center;
}
.column {
flex-direction: column;
}
.list {
padding: 20px;
background: #F5F5F5;
}
.img {
width: 94px;
height: 94px;
}
.item+.item {
margin-top: 20px;
}
.content {
padding-left: 20px;
background: #fff;
font-size: 12px;
flex: 1;
}
.even .img,
.odd .content {
order: 1;
}
.even .content,
.odd .img {
order: 2;
}
複製程式碼
卡片式佈局
卡片式佈局這個就很有綜合性了,先來分析下佈局吧。- 首先分為圖片和主體上下兩部分
- 主體又分為左右兩欄佈局
- 左欄按照普通的佈局來就行
- 右欄佔據剩餘寬度,設定
flex: 1;
,上下兩端對齊,靠右對齊,那麼可以採用使用column的佈局方式,主軸兩端對齊,交叉軸對齊於結尾處,表現為justify-content: space-between;align-items: flex-end;
程式碼如下:
<div class="container">
<div class="card">
<img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" alt="" class="card-img">
<div class="card-body flex">
<div class="card-body--left">
<div class="title">標題</div>
<div class="text">釋出者:誰知道</div>
<time class="time">欄目:天知道</time>
</div>
<div class="card-body--right flex column between">
<div class="share flex align-center">
<img src="http://uppic.fd.zol-img.com.cn/t_s501x2000/g5/M00/0D/0D/ChMkJ1ibsVeIeZ0QAACr6Uwo-6EAAZzpgMdtPAAAKwB105.jpg" alt="" class="share-icon">
<div class="share-text">分享</div>
</div>
<time class="time">釋出時間: 2019-01-02</time>
</div>
</div>
</div>
</div>
複製程式碼
.flex {
display: flex;
flex-direction: row;
}
.between {
justify-content: space-between;
}
.flex-center {
display: flex;
flex-direction: row;
justify-content: center;
}
.column {
flex-direction: column;
}
.container {
background: #F5F5F5;
padding: 32px;
}
.card {
width: 320px;
margin: 20px auto;
}
.card-img {
width: 100%;
}
.card-body {
padding: 20px;
background: #fff;
}
.title {
font-size: 16px;
color: #333;
}
.text {
font-size: 14px;
color: #666;
padding: 8px 0;
}
.card-body--right {
flex: 1;
align-items: flex-end;
}
.time {
font-size: 12px;
color: #999;
}
.share {
align-items: center;
}
.share-icon {
width: 40px;
height: 40px;
}
複製程式碼
聊天介面
簡單的分析一下佈局,一個別人發的,一個自己發的,也就靠左和靠右對齊的區別而已。
從正常的佈局來看,先是頭像,然後是一個三角形的箭頭(用border即可),再然後就是對話內容了。 反方向的話,就是控制一下這三個部分的order而已,還有就是外邊距的方向也得反一下。
跟之前的東西相比沒有什麼新鮮的,我就不貼程式碼了,要不然就太多了,當然了有需要的話可以留言,我可以放在評論區。
平時佈局的話,大家還是要注意多總結,先思考怎麼佈局更簡單,然後再著手寫程式碼,這樣可以省下很多時間的。flex在一維佈局確實是很強大的,基本上可以解決平時遇到的各種問題。grid在二維佈局方面相對而言更好用,都怪這**的相容性問題,要不然我們就有更多更好的方式可以選擇了。
那麼今天就先說到這裡吧(雖然大部分都是程式碼),如果大家還有什麼疑問或者指導性建議的話,歡迎評論。