這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 在使用 Vue 3 組件庫 Naive UI 的數據表格組件 DataTable 時碰到的問題,NaiveUI 的數據表格組件 DataTable 在固定頭部和列的示例中,在鍵盤操作下表格橫向滾動會有問題,本文是記錄下解決問題的過程 ...
1. Flex佈局與響應式佈局
1.1 為什麼需要響應式佈局?
在電腦PC端,使用浮動,定位同時使用像素px單位就可以完成大部分佈局,而且佈局完之後不會有大問題,但是到了移動端,移動設備的屏幕尺寸多種多樣,從小屏幕的智能手機到大屏幕的平板電腦,甚至是可穿戴設備,簡單地運用和PC端一樣的方式就會出現一些佈局和排列的問題。
這裡用PC端的縮放瀏覽器來舉個例子,當瀏覽器縮小的時候,百度就只顯示了一部分,無法在縮小的屏幕(瀏覽器視窗)中完全顯示。
移動前端中常說的 viewport (視口)就是瀏覽器中用於呈現網頁的區域。視口通常並不等於屏幕大小,特別是可以縮放瀏覽器視窗的情況下,為了確保在不同設備上都能夠提供良好的用戶體驗,需要使用響應式佈局來適應不同的屏幕尺寸。
1.2 響應式佈局的解決方案
響應式佈局有多種方案,比如:
- 媒體查詢:它允許根據設備的特性(如屏幕寬度、設備類型等)應用不同的樣式規則。通過使用媒體查詢,可以針對不同的屏幕尺寸和設備類型應用不同的樣式,從而實現響應式佈局。
- 流式佈局(百分比佈局):它是一種基於相對單位(如百分比)進行設計的佈局方式。在流式佈局中,元素的寬度和高度相對於父元素或視口進行計算,使得它們可以根據可用空間的大小進行自適應調整。流式佈局可以使頁面在不同屏幕尺寸下保持比例和流動性。
- Flex佈局:Flexbox是CSS3中的一種彈性盒子佈局模型,它提供了強大的排列和對齊功能,可以實現靈活的響應式佈局。通過使用Flexbox屬性和值,可以輕鬆地控制元素在容器中的位置、順序和大小。
- 柵格系統:柵格系統是一種將頁面劃分為多個網格列的佈局方式,通過定義網格列數和間距來佈局頁面內容。柵格系統通常與媒體查詢和流式佈局結合使用,以實現在不同屏幕尺寸下的響應式佈局。流行的柵格系統包括Bootstrap的柵格系統和Foundation的柵格系統。
本文主要介紹Flex佈局
1.3 Flex佈局的優越性
排列靈活,樣式簡單:Flex佈局在響應式解決方案中具有靈活的排列和對齊、自適應的彈性性質、自動換行和調整順序以及容器和項目的靈活性等優點,可以通過簡單的CSS屬性設置來控制元素在容器中的位置和佈局。通過設置容器的flex-direction、justify-content和align-items等屬性,可以輕鬆實現水平或垂直方向上的排列和對齊需求。這種靈活性使得在不同設備上適應不同佈局要求變得容易。相比起針對不同屏幕來設置的媒體查詢,相同的樣式設置就可以適配多種屏幕尺寸,Flex佈局非常的方便。
自動換行,調整順序:在移動設備上,屏幕空間有限,需要在有限的空間中合理佈局元素。Flex佈局可以通過設置flex-wrap屬性實現自動換行,使得項目可以在一行排列不下時自動換行到下一行。此外,還可以使用order屬性調整項目的顯示順序,以便在移動設備上優先顯示重要內容。這種自動換行和調整順序的特性使得在小屏幕設備上實現良好的用戶體驗變得簡單。
除了響應式佈局外,在PC端也可以利用Flex佈局來替代浮動和定位,完成很好的元素排列,讓開發者免去使用float,position來佈局的不便。最常見的八股文面試題,垂直水平居中就可以用flex佈局輕鬆完成,這也是工作中較為常用的方式。
2. Flex佈局定義
Flex佈局對於元素的內聯(行內)或塊級的性質是不關心的。在Flex佈局中,元素會根據容器和項目的屬性進行排列,無論元素是行內元素還是塊級元素。採用Flex佈局的元素,稱為Flex容器(flex container),簡稱”容器”。Flex容器的所有子元素自動成為容器成員,稱為Flex項目(flex item),簡稱”項目”。
容器預設存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做main start,結束位置叫做main end;交叉軸的開始位置叫做cross start,結束位置叫做cross end。
項目預設沿主軸排列。單個項目占據的主軸空間叫做main size,占據的交叉軸空間叫做cross size。
3. Flex容器屬性
3.1 開啟flex佈局display:flex
元素寫了這個屬性之後,就變成了一個flex的容器,就可以通過flex佈局相關的方式去操作排列子元素。
<style>
.parent{
display: flex;
width: 400px;
height: 200px;
background-color:blueviolet;
}
.child{
width: 100px;
height: 50px;
background-color: aqua;
border: 1px solid black;
}
</style>
</head>
<body>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
</div>
</body>
開啟flex佈局之後,沒有進行其他的設置,可以看到這個排列和沒有開啟flex佈局的時候是不一樣的,2個塊級元素,並沒有上下排列,而是已經排列在左右。開啟flex佈局後,容器中的項目預設會沿著主軸進行排列,此時沒有對容器和項目進行其他的設置,主軸也按照預設的方向水平放置,所以2個子盒子都沿著主軸水平排列了。
3.2 改變主軸的方向flex-direction屬性
flex-direction屬性決定了主軸的方向,所有容器中的項目都會根據主軸方向來排列。
flex-direction 屬性有四個可能的取值:
- row(預設值):Flex 項目水平排列,起點在左端,終點在右端。主軸從左到右。
- row-reverse:Flex 項目水平排列,起點在右端,終點在左端。主軸從右到左。
- column:Flex 項目垂直排列,起點在頂部,終點在底部。主軸從上到下。
- column-reverse:Flex 項目垂直排列,起點在底部,終點在頂部。主軸從下到上。
圖中顯示flex-direction的值為row時元素按順序從左往右橫向排列,子元素貼著父元素的左側
1 .parent{
2 display: flex;
3 flex-direction: row;
4 width: 400px;
5 height: 200px;
6 background-color:blueviolet;
7 }
圖中顯示flex-direction的值為row-reverse時元素按順序從右往左橫向排列,子元素貼著父元素的右側(代碼同上)
圖中顯示flex-direction的值為column時元素按順序從上往下豎向排列,子元素貼著父元素的頂部,這一點類似於常規的文檔流中塊級元素的排列(代碼同上)
圖中顯示flex-direction的值為column-reverse時元素按順序從下往上豎向排列,子元素貼著父元素的底部(代碼同上)
總的來說,flex-direction屬性雖然簡單,但是有重要的作用,可以
- 控制主軸方向:flex-direction 屬性決定了主軸的方向,即 Flex 項目在水平方向或垂直方向上的排列。通過設置不同的取值,我們可以實現水平排列(左到右或右到左)或垂直排列(從上到下或從下到上)的佈局。
- 確定起點和終點:flex-direction 屬性的取值影響了 Flex 項目在主軸上的起點和終點的位置。在 row 值下,起點位於左端,終點位於右端;在 row-reverse 值下,起點位於右端,終點位於左端;在 column 值下,起點位於頂部,終點位於底部;在 column-reverse 值下,起點位於底部,終點位於頂部。這種控制起點和終點的能力對於設計佈局非常有用。
- 影響項目排列順序:flex-direction 屬性還決定了 Flex 項目在主軸上的排列順序。在預設的 row 值下,Flex 項目按照其在 HTML 結構中的順序從左到右排列;在 row-reverse 值下,項目按照相反的順序從右到左排列;在 column 值下,項目按照結構順序從上到下排列;在 column-reverse 值下,項目按照相反的順序從下到上排列。通過改變項目的排列順序,我們可以調整 Flex 佈局的外觀和行為。
3.3 改變換行方式flex-wrap屬性
flex-wrap屬性決定了換行相關的策略。它決定了當彈性容器的寬度不足以容納所有子元素時,是否允許子元素換行並如何排列。
它有幾個常用的屬性值:
- nowrap(預設值):子元素不換行,儘可能地將它們放在一行內,即使溢出彈性容器的邊界。
- wrap:如果子元素在一行內放不下,將它們進行換行,從新行開始排列。
- wrap-reverse:與 wrap 相同,但換行時的排列順序與正常順序相反。
當沒有寫flex-wrap屬性時,所有元素會預設沿著主軸在一行(或一列)排列。這也就和寫了flex-wrap: nowrap是等效的
在已經給子項目設置了100px的寬度的情況下,6個項目仍然會排在同一行,而此時父元素的寬度也只有400px,說明此時子項目的寬度已經被壓縮了變成了小於100px。
1 <style>
2 .parent {
3 display: flex;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 100px;
11 height: 50px;
12 background-color: aqua;
13 border: 1px solid black;
14 }
15 </style>
16 <body>
17 <div class="parent">
18 <div class="child">1</div>
19 <div class="child">2</div>
20 <div class="child">3</div>
21 <div class="child">4</div>
22 <div class="child">5</div>
23 <div class="child">6</div>
24 </div>
25 </body>
當希望子項目完成換行的時候可以設置flex-wrap: wrap
明顯可以看到,圖片已經完成了換行效果,但是這裡上下兩行元素出現了空隙,似乎與預期效果不符合,這是由於多行對齊時的align-content的預設值導致的,具體align-content用法會在後文解釋。
1 .parent {
2 display: flex;
3 flex-wrap: wrap;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 100px;
11 height: 50px;
12 background-color: aqua;
13 border: 1px solid black;
14 }
當換行屬性設置為flex-wrap: wrap-reverse,也會完成換行,但是換行的順序與前面相反,第一行會在最下麵,最後一行在上面
3.4 主軸對齊方式justify-content屬性
justify-content是flex佈局中的重要屬性之一,用於定義和調整彈性容器中項目在主軸上的對齊方式。它控制項目沿著主軸的分佈方式,包括項目之間的間距、對齊和對齊方式的調整。
這個屬性常用的有以下幾個值
- flex-start(預設值):將項目對齊到彈性容器的起始位置。項目靠主軸起始端對齊。
- flex-end:將項目對齊到彈性容器的末尾位置。項目靠主軸末尾端對齊。
- center:將項目在主軸上居中對齊。項目在主軸上平均分佈,兩端留有相同的空白。
- space-between:將項目在主軸上平均分佈,並使項目之間的間距相等。首個項目對齊到主軸起始端,最後一個項目對齊到主軸末尾端。
- space-around:將項目在主軸上平均分佈,並使項目之間的間距相等。首尾兩端的間距是相鄰項目間距的一半。
- space-evenly:將項目在主軸上平均分佈,並使項目之間的間距相等。首尾兩端和相鄰項目之間的間距相等。
不寫justify-content或者justify-content的值為flex-start時,flex容器內部的項目會按順序沿著主軸排列,也就是當主軸是水平的時候就橫過來排列,主軸是豎直的就豎過來排列。
以較常見的flex-direction取預設值row的時候舉例,有類似於float:left的效果,但是不會出現子元素浮動後脫離文檔流導致父元素高度塌陷的問題。
1 .parent {
2 display: flex;
3 justify-content: flex-start;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
justify-content的值為flex-end時,子元素也就是flex容器會靠主軸的終點處對齊,與前面的flex-start呈現相反的對齊排列效果。
以較常見的flex-direction取預設值row的時候舉例,類似於float:right的效果,但是與右浮動不同的是右浮動會導致元素倒序排列而flex-end會保持元素的順序,元素的排列順序仍然是1,2,3。
1 <div class="parent">
2 <div class="child">1</div>
3 <div class="child">2</div>
4 <div class="child">3</div>
5 </div>
對於右浮動會出現倒序的原因,這裡進行簡單的解釋:
浮動的元素直到碰到邊緣或另一個浮動元素的邊緣為止,而代碼又是從上往下執行,對於第一個child會優先進行浮動,碰到父盒子右邊緣,結束,第二個child再開始浮動,碰到第一個child的左邊緣再結束,第三個child在第二個child浮動結束後再浮動,就貼著第二個child左邊緣。
解決右浮動倒序的方法可以有以下幾種:
- 利用flex佈局的flex-end,如上圖所示
- 倒序書寫元素,這樣就可以正序排列了。
- 對於多個右浮動的child,再在外面加一層div包裹,先讓外層的div右浮動(只有一個盒子,不會出現順序問題的同時又能靠右對齊),然後讓每個child左浮動(左浮動不會導致順序出現問題,又可以實現浮動效果),代碼和圖片如下
<style> .parent { width: 400px; height: 200px; background-color: blueviolet; } .wrapper { float: right; } .child { float: left; width: 100px; height: 50px; background-color: aqua; border: 1px solid black; } </style> </head> <body> <div class="parent"> <div class="wrapper"> <div class="child">1</div> <div class="child">2</div> <div class="child">3</div> </div> </div> </body>
justify-content的值為center時,flex容器內的元素在主軸上居中對齊,向兩邊平均分佈
以較常見的flex-direction取預設值row的時候舉例,圖中利用flex佈局的justify-content:center 可以非常方便地實現塊級元素的居中對齊
justify-content的值為space-between時,項目會在主軸兩端對齊,中間平均排列,讓不同的項目之間的間距相等
這裡將每個child的寬度調成50px讓多個盒子都能呈現在父容器內(同時避免尺寸發生變化)以展示space-between的效果。
這種佈局形式在真實開發中也較為常用,有許多場景都需要兩端對齊後,中間均分空隙。
以較常見的flex-direction取預設值row的時候舉例,可以看到子項目中的間距都是相同的。在沒有設置任何margin的情況下,元素也可以完成分離。
1 .parent {
2 display: flex;
3 justify-content: space-between;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 50px;
11 height: 50px;
12 background-color: aqua;
13 border: 1px solid black;
14 }
justify-content的值為space-around時,每個項目自身的左右間距會相等,類似於設置了左右兩邊相同的margin值
以較常見的flex-direction取預設值row的時候舉例,看起來首尾元素間距更窄,是因為對於中間元素一共有2份間距,前一個元素的右間距+後一個元素的左間距,所以中間的間距是首尾的兩倍。
justify-content的值為space-evenly時,所有項目的間距都會相等,前面提到的space-around會讓每個項目自身都具有相同左右邊距,導致中間的間距疊加成立首尾的2倍。而space-evenly中會讓所有的間距都相等,包括剛纔所提到的首尾和中間。
以較常見的flex-direction取預設值row的時候舉例,所有間距都相同。
3.5 交叉軸單行對齊align-items屬性
與justify-content對應的,align-items用於定義和調整彈性容器中項目在交叉軸上的對齊方式,它同樣也控制項目沿著交叉軸的分佈方式,包括項目之間的間距、對齊和對齊方式的調整。
這個屬性有以下幾個常用的值
- stretch(預設值):將項目在交叉軸上拉伸以填充整個彈性容器。項目將沿交叉軸方向拉伸至與容器的交叉軸尺寸相等。
- flex-start:將項目對齊到彈性容器的交叉軸起始位置。項目靠交叉軸起始端對齊。
- flex-end:將項目對齊到彈性容器的交叉軸末尾位置。項目靠交叉軸末尾端對齊。
- center:將項目在交叉軸上居中對齊。項目在交叉軸上平均分佈,上下留有相同的空白。
- baseline:將項目在交叉軸上與其基線對齊。項目的基線與其他項目的基線對齊。
這裡先從預設不寫這個屬性來看,雖然align-items里也有和justify-content相同的flex-start值,但是這裡的預設值並不是flex-start而是stretch,stretch的意思是伸展、延伸,也就是說寫了stretch之後(或者直接不寫align-items讓他取預設值),項目會在交叉軸上伸展。
以沒有寫高度的項目舉例
1 .parent {
2 display: flex;
3 justify-content: stretch;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 50px;
11 background-color: aqua;
12 border: 1px solid black;
13 }
註意,以上代碼中,子元素沒有設置高度,所以flex項目完成拉伸並且在交叉軸上填滿整個父容器的高度(或寬度),當然如果項目分多行排列,也會撐滿整個父容器,每個項目的高度會被拉伸到:父元素高度/行數。
如果子項目已經設置了高度,那麼這個屬性就不會生效,不會再去拉伸項目。同樣的如果主軸是垂直的,項目沒有寫寬度,也會橫向撐滿整個容器
1 .parent {
2 display: flex;
3 align-items: stretch;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 50px;
11 height: 50px;
12 background-color: aqua;
13 border: 1px solid black;
14 }
align-items為flex-start時,子項目都沿著交叉軸靠著交叉軸的起點對齊
這裡因為只有一行(沒有設置換行屬性,也沒有一行排列不下),整個容器的上端也就是交叉軸的起點, 所以看起來和上面的圖沒什麼區別。
align-items為flex-end時,子項目都沿著交叉軸靠著交叉軸的終點對齊
和上圖相反的是,設置了這個屬性,一行的項目就來到了容器底部,因為預設情況下交叉軸從上往下,容器的底部也就是整個交叉軸的終點
align-items為center時,子項目都沿著交叉軸靠著交叉軸居中對齊,往兩邊平均分佈
設置了center後,子項目來到居中的位置。這也是在flex佈局中最常用的居中技巧之一。如果需要垂直方向的居中,可以直接使用flex佈局並且寫上align-items: center。
align-items為baseline時,項目會按照文本的基線對齊
先針對第二個項目設置了一個padding,這樣第二個項目的文字就會被擠下去,所以文字就不會在同一條基線上了
1 <style>
2 .parent {
3 display: flex;
4 width: 400px;
5 height: 200px;
6 background-color: blueviolet;
7 }
8
9 .child {
10 width: 50px;
11 height: 50px;
12 background-color: aqua;
13 border: 1px solid black;
14 }
15
16 #two {
17 padding-top: 10px;
18 }
19 </style>
20 <body>
21 <div class="parent">
22 <div class="child">1</div>
23 <div class="child" id="two">2</div>
24 <div class="child">3</div>
25 <div class="child">4</div>
26 <div class="child">5</div>
27 <div class="child">6</div>
28 </div>
29 </body>
如果設置align-items: baseline之後,項目明顯都在同一條基線上。
3.6 交叉軸多行對齊align-content屬性