Flex 是 Flexible Box 的縮寫,意為"彈性布局",它旨在提供一種更有效的方式來布局、對齊和分配容器中項目之間的空間,即使這些項目的大小未知或是動態(因此稱為 "flex")。
Flex 布局背后的主要思想是讓容器能夠改變其項目的寬度/高度(和順序),以最好地填充可用空間(主要是為了適應各種顯示設備和屏幕大小)。flex 容器擴展項目以填充可用空間,或收縮項目以防止溢出。
最重要的是,Flexbox 布局與常規布局(基于垂直的塊和基于水平的內聯)相比是方向無關的。雖然這些方法對頁面很有效,但它們缺乏靈活性來支持大型或復雜的應用程序(尤其是在方向改變、調整大小、拉伸、收縮等方面)。
Flex 布局在2009年由 W3C 提出的。它在所有的瀏覽器都支持。
注意:Flexbox 布局最適合應用程序的組件和小規模布局,而 Grid 布局則適用于大規模布局。我們將在下一篇講解 Grid 布局。
以下內容參考 Flexbox30,圖片截自 A Complete Guide to Flexbox
基礎概念
為了使 Flexbox 正常工作,您需要設置父子關系。父級是 Flex 容器,其中的所有內容都是子級或 Flex 項。
Flex 容器僅環繞其直接子容器。因此,沒有孫子或孫子孫輩的關系。只有父母??直系子女!只要存在父子關系,就可以建立 Flexbox。因此,孩子也可以成為其孩子的伸縮容器。但這將是一個單獨的 flex 容器。而且它不會繼承祖父母的 flex 屬性。
這里有一篇關于不能將文本容器設置為 flexbox 容器 Never make your text container a flexbox container。
Flexbox 在2軸系統中運行:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸是您將伸縮項目如何放置在伸縮容器中的定義方向。確定橫軸非常簡單,它是在垂直于主軸的方向上進行的。
記住不要把他比作數學上的 x 和 y 軸。因為 x 軸并不總是主軸。這可能會讓你出錯。
在每個軸上都有一個起點和終點。如果在主軸上,則將起始位置稱為 main start,將結束位置稱為 main end。相同的概念適用于交叉軸。知道開始和結束很重要,因為您可以控制彈性項目的放置位置。
項目默認沿主軸排列。單個項目占據的主軸空間叫做 main size
,占據的交叉軸空間叫做 cross size
。
屬性
父容器和子項目都有自己的一套屬性。
父容器
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
子項目
flex-grow
flex-shrink
flex-basis
flex
order
align-self
父容器
flex 容器有2種類型:flex 將創建一個塊級 flex 容器,inline-flex 將創建一個 inline 級 flex 容器。
.parent {
display: flex /* default */ | inline-flex;
}
很簡單地解釋,塊元素占據了容器的整個寬度。它們看起來像構建塊,其中每個構建塊彼此堆疊。內聯元素僅占用其所需的空間。因此,它們似乎排成一行,或者彼此并排。
flex-wrap
默認情況下,彈性項目將嘗試使其自身收縮以適合一行,換句話說,不進行換行。但是,如果您希望 flex 項保持其大小并在容器中的多行中溢出,則可以使用 flex-wrap: warp;
。此屬性將使容器中的彈性項目占用多行。
.parent {
flex-wrap: nowrap /* default */ | wrap | wrap-reverse;
}
flex-wrap
允許 flex 項在單獨的行上進行包裝。但有了 align-content
,我們可以控制那些項目行在橫軸上的對齊方式。由于這僅適用于包裝的項目,所以如果只有一行 flex 項,則此屬性不會有任何效果。
flex-flow
flex-flow
是 flex-direction
和 flex-wrap
的簡寫。默認值為 row nowrap。如果僅設置一個值,則未設置的屬性將采用默認值。
.parent {
flex-flow: row nowrap /* default */ | <flex-direction> <flex-wrap> | <flex-direction> | <flex-wrap>;
}
flex-direction
定義主軸的屬性。記住主軸可以是水平或垂直的。因此,如果我們希望主軸水平,則稱為行。如果我們希望它是垂直的,那就叫做專欄。另外,請記住我們有一個主要的起點和終點。我們只需添加一個反向后綴即可將我們的“主要起點”設置為反向。
.parent {
flex-direction: row /* default */ | row-reverse | column | column-reverse;
}
justify-content
justify-content
設置沿主軸對齊的屬性。align-items
設置沿橫軸對齊的屬性。記住橫軸始終垂直于主軸。
.parent {
justify-content: flex-start /* default */ | flex-end | center | space-around | space-between | space-evenly;
}
主軸也可以垂直放置。在這種情況下,將 flex-direction
設置為 column。
.parent {
flex-direction: column;
justify-content: flex-start /* default */ | flex-end | center | space-around | space-between | space-evenly;
}
align-items
.parent {
align-items: stretch /* default */ | flex-start | flex-end | center | baseline;
}
現在,讓我們看一下如果交叉軸水平放置,則彈性項目如何對齊。換句話說,伸縮方向是列。
.parent {
flex-direction: column;
align-items: stretch /* default */ | flex-start | flex-end | center | baseline;
}
align-content
align-content
屬性定義了多根軸線的對齊方式。如果項目只有一根軸線,該屬性不起作用。
.parent {
align-content: stretch /* default */ | flex-start | flex-end | center | space-between | space-around;
}
space-evenly 和 space-around
在 space-evenly
中,彈性項目之間的空白空間始終相等。
但是,在 space-around
上,只有內部項目之間的間距相等。第一項和最后一項將僅分配一半的間距。使它的視覺外觀更加散布
子項目
order
默認情況下,彈性項目的顯示順序與在代碼中顯示的順序相同。但是,如果您要更改該怎么辦?沒問題!使用 order
屬性更改商品的順序。
.child {
order: 0 /* default */ | <number>;
}
flex-grow
Flexbox 非常適合響應式設計。flex-grow
屬性允許我們的 flex 項在必要時增長。因此,如果我的容器中有多余的可用空間,我可以告訴某個特定項目按一定比例將其填滿。
.child {
flex-grow: 0 /* default */ | <number>;
}
flex-shrink
如果有伸縮空間,flex-grow
將會擴展以填充額外的空間。相反 flex-shrink
當空間不足時將會控制 flex 項目縮小到適合的程度。請注意,數字越大,縮小幅度越大。
.child {
flex-shrink: 1 /* default */ | <number>;
}
你可以在 flex-grow-calculation 和 flex-shrink-calculation 查看瀏覽器如何幫我們自動處理 flex-grow
、flex-shrink
。
flex-basis
使用 flex-basis
屬性,可以設置項目的初始大小。您可以將此屬性視為 flex 項目的寬度。
因此,您的下一個問題可能是 width
和 flex-basis
之間的區別是什么。當然,您仍然可以使用 width
,它將仍然有效。
它起作用的原因是,如果未設置 flex-basis
,它將默認為 width
。因此,您的瀏覽器將始終嘗試將 flex-basis
值用作大小指示器。如果找不到它,那就別無選擇,只能使用您的 width
屬性。不要讓瀏覽器做額外的工作。以正確的 flex 方法進行操作,并使用flex-basis
。
.child {
flex-basis: auto /* default */ | <width>;
}
當一個項目具有 flex-basis
和 width
時,瀏覽器將始終使用 flex-basis
設置的值。但要注意,如果同時設置了 min-width
和 max-width
。在這些情況下,flex-basis
將丟失,并且不會用作寬度。
flex
flex 是上面所提到的 flex-grow
、flex-shrink
和 flex-basis
的簡寫形式。如果你足夠了解它們的特性,請使用簡寫吧!!!
.child {
flex: 1 0 auto /* default */ |
<flex-grow> <flex-shrink> <flex-basis> |
<flex-grow> |
<flex-basis> |
<flex-grow> <flex-basis> |
<flex-grow> <flex-shrink>;
/* 相當于: */
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
}
align-self
align-items
屬性可以沿著橫軸設置 flex 項。align-items
的問題是它強制所有 flex 項使用規則。
但是如果你想讓他們中的一個打破規則,你可以使用 align-self
。此屬性接受為 align-items
提供的所有相同值,因此您可以輕松脫離包裝??
.child-1 {
align-self: stretch /* default */ | flex-start | flex-end | center | baseline;
}
技巧
垂直水平居中元素
方式一
.container {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
}
方式二
.container {
display: flex;
}
.container > div {
margin: auto;
}
對齊 Flexbox 子元素的另一種方法是使用自動頁邊距。盡管這不是 Flexbox 屬性,但要意識到這一點仍然很重要,因為它與 Flexbox 有非常有趣的關系。Bonus: Aligning with Auto Margins
重新排序
.container > .top {
order: 1;
}
.container > .bottom {
order: 2;
}
截斷文本
.parent {
display: flex;
align-items: center;
padding: 10px;
margin: 30px 0;
}
.child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child > h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.truncated {
flex: 1;
h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
移動布局
創建固定高度的頂欄和動態高度的內容區域。
.container {
display: flex;
flex-direction: column;
}
.container > .top {
flex: 0 0 60px;
}
.container > .content {
flex: 1 0 auto;
}
流式布局
自動用適當數量的盒子填充可用空間。
.container {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
gap: 1rem;
}
.container > * {
flex: 1 1 10ch;
}
響應導航欄
.nav {
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
list-style: none;
margin: 0;
background: deepskyblue;
}
.nav a {
text-decoration: none;
display: block;
padding: 1em;
color: white;
}
.nav a:hover {
background: #1565C0;
}
@media all and (max-width: 800px) {
.nav {
justify-content: space-around;
}
}
@media all and (max-width: 600px) {
.nav {
flex-flow: column wrap;
padding: 0;
}
.nav a {
text-align: center;
padding: 10px;
border-top: 1px solid rgba(255, 255, 255,0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.nav li:last-of-type a {
border-bottom: none;
}
}
類似于表
.container {
display: flex;
}
.container > .checkbox {
flex: 1 0 20px;
}
.container > .subject {
flex: 1 0 400px;
}
.container > .date {
flex: 1 0 120px;
}
這將創建寬度不同的列,但大小會根據具體情況而相應調整。
固定腳部
HTML 結構
<section>
<header></header>
<main></main>
<footer></footer>
</section>
方式一
section {
display: flex;
flex-direction: column;
height: 100vh;
}
main {
flex: 1;
}
方式二
section {
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
砌體布局
.masonry-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 600px;
.masonry-brick {
margin: 0 .825rem .825rem 0;
border-radius: 1rem;
}
}
/* or */
.masonry-container {
display: flex;
flex-wrap: wrap;
.masonry-brick {
flex: 1 0 auto;
height: 150px;
margin: 0 .825rem .825rem 0;
border-radius: 1rem;
}
}
圣杯布局
html 結構
<div class="container">
<header class="header">Header</header>
<article class="main">lorem</article>
<aside class="aside aside-1">Aside 1</aside>
<aside class="aside aside-2">Aside 2</aside>
<footer class="footer">Footer</footer>
</div>
css
.container {
display: flex;
flex-flow: row wrap;
text-align: center;
}
.container > * {
padding: 10px;
flex: 1 100%;
}
.main {
text-align: left;
}
@media all and (min-width: 600px) {
.aside { flex: 1 0 0; }
}
@media all and (min-width: 800px) {
.main { flex: 3 0px; }
.aside-1 { order: 1; }
.main { order: 2; }
.aside-2 { order: 3; }
.footer { order: 4; }
}
雙飛翼布局
雙飛翼布局其實是根據圣杯布局演化出來的一種布局。
.container {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
height: 100%;
}
.left,
.right {
width: 200px;
flex-shrink: 1;
}
.main {
flex-grow: 1;
}
兩列布局
.container {
display: flex;
}
.left {
width: 200px;
height: 100%;
}
.right {
flex: 1;
height: 100%;
}