CSS 佈局介紹
本文將回顧我們在之前的模組中已經接觸過的一些 CSS 佈局功能,例如不同的 display 值,並介紹一些我們將在本模組中介紹的概念。
CSS 頁面佈局技術允許我們獲取 Web 頁面中包含的元素,並控制它們相對於以下因素的位置:它們在正常佈局流中的預設位置、周圍的其他元素、它們的父容器以及主視口/視窗。我們將在本模組中更詳細介紹的頁面佈局技術有
- 正常流
display屬性- Flexbox
- 網格
- 浮動
- 定位
- 表格佈局
- 多列布局
每種技術都有其用途、優勢和劣勢。沒有一種技術旨在孤立使用。通過了解每種佈局方法的設計目的,您將能夠更好地理解哪種方法最適合每項任務。
正常流
正常流是瀏覽器在您不控制頁面佈局時預設如何佈局 HTML 頁面的方式。讓我們來看一個簡單的 HTML 示例
<p>I love my cat.</p>
<ul>
<li>Buy cat food</li>
<li>Exercise</li>
<li>Cheer up friend</li>
</ul>
<p>The end!</p>
預設情況下,瀏覽器將如下顯示此程式碼
請注意,HTML 的顯示順序與其在原始碼中出現的順序完全相同,元素一個疊放在另一個上面——第一段,然後是無序列表,然後是第二段。
一個接一個出現的元素稱為塊級元素,與內聯元素形成對比,內聯元素像段落中的單個單詞一樣並排出現。
注意:塊級元素內容的佈局方向稱為塊級方向。塊級方向在英語等具有水平書寫模式的語言中垂直執行。在日語等任何具有垂直書寫模式的語言中,它將水平執行。相應的內聯方向是內聯內容(如句子)將執行的方向。
對於頁面上的許多元素,正常流將建立您所需的佈局。但是,對於更復雜的佈局,您需要使用 CSS 中提供的一些工具來更改此預設行為。從結構良好的 HTML 文件開始非常重要,因為您可以處理預設的佈局方式,而不是與之對抗。
可以在 CSS 中更改元素佈局方式的方法有
display屬性——標準值(如block、inline或inline-block)可以更改元素在正常流中的行為,例如,使塊級元素的行為像內聯級元素(請參閱 CSS 盒子型別 以獲取更多資訊)。我們還有一些透過特定display值啟用的完整佈局方法,例如 CSS 網格 和 Flexbox,它們會更改子元素在其父元素內的佈局方式。- 浮動 — 應用像
left這樣的float值可以導致塊級元素沿著某個元素的一側環繞,就像雜誌版式中圖片周圍有時會有文字環繞一樣。 position屬性 — 允許你精確控制盒子在其他盒子內部的位置。static定位是正常流中的預設值,但你可以使用其他值來改變元素的佈局方式,例如,將其固定到瀏覽器視口頂部。- 表格佈局 — 為樣式化HTML表格的部分而設計的特性可以使用
display: table和相關屬性應用於非表格元素。 - 多列布局 — 多列布局屬性可以使塊的內容以多列的形式佈局,就像你在報紙上看到的那樣。
display 屬性
在CSS中實現頁面佈局的主要方法都涉及為display屬性指定值。此屬性允許我們更改某物顯示的預設方式。正常流中的所有內容都具有display的預設值;即元素設定為行為的預設方式。例如,英文段落一個接一個顯示的事實是因為它們使用display: block進行樣式化。如果你在一個段落內的一些文本週圍建立一個連結,則該連結將與文字的其餘部分保持內聯,並且不會換行。這是因為<a>元素預設情況下為display: inline。
你可以更改此預設顯示行為。例如,<li>元素預設情況下為display: block,這意味著列表項在我們的英文文件中一個接一個地顯示。如果我們將顯示值更改為inline,它們將並排顯示,就像句子中的單詞一樣。你可以為任何元素更改display的值這一事實意味著你可以根據語義含義選擇HTML元素,而無需擔心它們的外觀。它們的外觀是可以更改的。
除了能夠透過將專案從block更改為inline反之亦然來更改預設顯示外,還有一些更復雜的佈局方法從display的值開始。但是,在使用這些方法時,通常需要呼叫其他屬性。在我們討論佈局時最重要的兩個值是display: flex和display: grid。
Flexbox
Flexbox是彈性盒子佈局CSS模組的簡稱,旨在使我們能夠輕鬆地在一維上佈局內容——要麼作為一行,要麼作為一列。要使用flexbox,你需要將display: flex應用於要佈局的元素的父元素;然後,其所有直接子元素都將成為彈性專案。我們可以在一個簡單的示例中看到這一點。
設定display: flex
下面的HTML標記為我們提供了一個具有wrapper類的容器元素,在其內部是三個<div>元素。預設情況下,這些元素將顯示為塊級元素,即在我們的英文文件中一個接一個地顯示。
但是,如果我們將display: flex新增到父元素,這三個專案現在將排列成列。這是因為它們成為了彈性專案,並受到flexbox在彈性容器上設定的一些初始值的影響。它們以行顯示,因為父元素的flex-direction屬性的初始值為row。它們看起來都垂直拉伸,因為其父元素的align-items屬性的初始值為stretch。這意味著專案會拉伸到彈性容器的高度,在本例中,由最高的專案定義。所有專案都排列在容器的開頭,在行的末尾留下任何額外的空間。
.wrapper {
display: flex;
}
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
</div>
設定flex屬性
除了可以應用於彈性容器的屬性外,還可以應用於彈性專案的屬性。除其他事項外,這些屬性可以更改專案的彈性方式,使它們能夠根據可用空間進行擴充套件或收縮。
作為一個簡單的例子,我們可以將flex屬性新增到我們所有的子專案中,併為其指定值為1。這將導致所有專案增長並填充容器,而不是在末尾留下空間。如果有更多空間,則專案將變得更寬;如果空間較小,則專案將變得更窄。此外,如果你向標記中新增另一個元素,則其他所有專案都將變小以騰出空間;所有專案一起繼續佔據所有空間。
.wrapper {
display: flex;
}
.wrapper > div {
flex: 1;
}
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
</div>
注意:這只是對flexbox中可能實現的功能的非常簡短的介紹。要了解更多資訊,請參閱我們的Flexbox文章。
網格佈局
雖然flexbox專為一維佈局而設計,但網格佈局專為二維佈局而設計——將內容排列成行和列。
設定display: grid
與flexbox類似,我們使用其特定的顯示值——display: grid啟用網格佈局。下面的示例使用與flex示例類似的標記,包含一個容器和一些子元素。除了使用display: grid外,我們還使用grid-template-rows和grid-template-columns屬性分別為父元素定義了一些行和列軌道。我們定義了三列,每列為1fr,以及兩行,每行100px。我們不需要對子元素設定任何規則;它們會自動放置到我們建立的網格單元格中。
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 100px;
gap: 10px;
}
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
<div class="box4">Four</div>
<div class="box5">Five</div>
<div class="box6">Six</div>
</div>
在網格上放置專案
擁有網格後,你可以顯式地在網格上放置專案,而不是依賴於上面看到的自動放置行為。在下面的下一個示例中,我們定義了相同的網格,但這次有三個子專案。我們使用grid-column和grid-row屬性設定了每個專案的開始和結束線。這會導致專案跨越多個軌道。
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 100px;
gap: 10px;
}
.box1 {
grid-column: 2 / 4;
grid-row: 1;
}
.box2 {
grid-column: 1;
grid-row: 1 / 3;
}
.box3 {
grid-row: 2;
grid-column: 3;
}
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
</div>
注意:這兩個示例僅揭示了網格佈局強大功能的一小部分。要了解更多資訊,請參閱我們的網格佈局文章。
本指南的其餘部分涵蓋其他佈局方法,這些方法對於頁面的主要佈局不太重要,但仍然有助於完成特定任務。通過了解每個佈局任務的本質,你很快就會發現,當你檢視設計的特定元件時,最適合它的佈局型別通常會很清楚。
浮動
使元素浮動會更改該元素及其在正常流中跟隨它的塊級元素的行為。浮動元素將移動到左側或右側並從正常流中移除,並且周圍的內容會環繞它。
float屬性有四個可能的值
left— 將元素浮動到左側。right— 將元素浮動到右側。none— 指定根本沒有浮動。這是預設值。inherit— 指定應從元素的父元素繼承float屬性的值。
在下面的示例中,我們將一個<div>向左浮動,並在右側設定margin以將周圍的文字推離它。這使我們能夠實現文字環繞方框元素的效果,並且這是你對現代網頁設計中使用的浮動需要了解的大部分內容。
<h1>Simple float example</h1>
<div class="box">Float</div>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam
dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus
ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus
laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum,
tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus
neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat
volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros
pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec
lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.
</p>
.box {
float: left;
width: 150px;
height: 150px;
margin-right: 30px;
}
注意:在我們的關於float和clear屬性的課程中完整解釋了浮動。在flexbox和網格佈局等技術之前,浮動被用作建立列布局的方法。你可能仍然會在網路上遇到這些方法;我們將在關於傳統佈局方法的課程中介紹這些方法。
定位技術
定位允許你將元素從它在正常流中放置的位置移動到另一個位置。定位不是建立頁面主要佈局的方法;它更多的是關於管理和微調頁面上特定專案的位置。
但是,有一些有用的技術可以獲得依賴於position屬性的特定佈局模式。瞭解定位也有助於理解正常流及其含義,以及將專案移出正常流的含義。
有五種型別的定位你應該瞭解
- 靜態定位是每個元素獲得的預設值。它只是意味著“將元素放置到文件佈局流中的正常位置——這裡沒有什麼特別的”。
- 相對定位允許你修改元素在頁面上的位置,相對於其在正常流中的位置移動它,以及使其與頁面上的其他元素重疊。
- 絕對定位將元素完全移出頁面的正常佈局流,就像它位於自己的單獨圖層上一樣。從那裡,你可以將其固定到相對於其最近的已定位祖先的邊緣的位置(如果沒有任何其他祖先被定位,則變為
<html>)。這對於建立複雜的佈局效果很有用,例如選項卡式框,其中不同的內容面板彼此疊加,並根據需要顯示和隱藏,或者預設情況下位於螢幕外的資訊面板,但可以使用控制按鈕使其滑入螢幕。 - 固定定位與絕對定位非常相似,只是它相對於瀏覽器視口而不是另一個元素固定元素。這對於建立效果很有用,例如一個持久導航選單,該選單始終停留在螢幕上的相同位置,而其他內容則在滾動。
- 粘性定位是一種更新的定位方法,它使元素的行為類似於
position: relative,直到它到達視口定義的偏移量,此時它會像position: fixed一樣工作。
簡單的定位示例
為了讓你熟悉這些頁面佈局技術,我們將向你展示幾個快速示例。我們的示例都將具有相同的HTML結構(標題後跟三個段落),如下所示
<h1>Positioning</h1>
<p>I am a basic block level element.</p>
<p class="positioned">I am a basic block level element.</p>
<p>I am a basic block level element.</p>
此HTML將預設使用以下CSS進行樣式化
body {
width: 500px;
margin: 0 auto;
}
p {
background-color: rgb(207 232 220);
border: 2px solid rgb(79 185 227);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
background: rgb(255 84 104 / 30%);
border: 2px solid rgb(255 84 104);
}
呈現的輸出如下所示
相對定位
絕對定位
絕對定位用於完全從正常流中移除元素,而是使用相對於包含塊邊緣的偏移量對其進行定位。
回到我們最初的非定位示例,我們可以新增以下CSS規則來實現絕對定位
.positioned {
position: absolute;
top: 30px;
left: 30px;
}
在這裡,我們為中間段落指定了absolute的position值,以及與之前相同的top和left屬性。新增此程式碼將產生以下結果
這非常不同!已定位的元素現在已完全與頁面的其餘佈局分離,並位於其頂部。其他兩個段落現在並排放置,就像它們的已定位同級元素不存在一樣。top和left屬性對絕對定位元素的影響與對相對定位元素的影響不同。在這種情況下,偏移量是從頁面的頂部和左側計算的。可以更改成為此容器的父元素,我們將在關於定位的課程中介紹這一點。
固定定位
固定定位以與絕對定位相同的方式將元素從文件流中移除。但是,偏移量不是從容器應用的,而是從視口應用的。由於專案相對於視口保持固定,因此我們可以建立效果,例如在頁面在其下方滾動時保持固定的選單。
對於此示例,我們的HTML包含三段文字,以便我們能夠滾動頁面,以及一個具有position: fixed屬性的框。
<h1>Fixed positioning</h1>
<div class="positioned">Fixed</div>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam
dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus
ut, rutrum luctus orci.
</p>
<p>
Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed
auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci
vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex
malesuada et.
</p>
<p>
In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet
turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas
augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id
ornare felis, eget fermentum sapien.
</p>
.positioned {
position: fixed;
top: 30px;
left: 30px;
}
粘性定位
粘性定位是我們可用的最終定位方法。它將相對定位與固定定位混合在一起。當專案具有position: sticky時,它將在正常流中滾動,直到到達我們定義的視口偏移量。此時,它會變得“粘住”,就像應用了position: fixed一樣。
.positioned {
position: sticky;
top: 30px;
left: 30px;
}
注意:要了解更多關於定位的資訊,請參閱我們的定位文章。
表格佈局
在檢視舊網站上的原始碼時,你可能會發現表格已用於佈局表單。HTML表格應保留用於顯示錶格資料。將表格用於表格資料以外的任何用途都有很多問題:表格佈局不靈活,標記非常繁重,難以除錯,並且語義錯誤(例如,螢幕閱讀器使用者難以瀏覽表格佈局)。
當你使用表格標記時,網頁上表格的外觀是由於一組定義其佈局的CSS屬性。這些相同的屬性也可用於佈局不是表格的元素,這種用法有時被稱為“使用CSS表格”。下面的示例顯示了這種用法。
讓我們看一個例子。首先,一些簡單的標記建立了一個HTML表單。每個輸入元素都有一個標籤。我們還在一個段落內包含了一個標題;儘管另一個選擇是使用帶有<legend>的<fieldset>。每個標籤/輸入對都包裝在一個<div>中,用於佈局目的。
<form>
<p>First of all, tell us your name and age.</p>
<div>
<label for="fname">First name:</label>
<input type="text" id="fname" />
</div>
<div>
<label for="lname">Last name:</label>
<input type="text" id="lname" />
</div>
<div>
<label for="age">Age:</label>
<input type="text" id="age" />
</div>
</form>
至於CSS,除了display屬性的使用外,大多數都是相當普通的。<form>、<div>s以及<label>s和<input>s已被告知像表格、表格行和表格單元格一樣顯示。基本上,它們將像HTML表格標記一樣工作,從而導致標籤和輸入預設情況下很好地對齊。我們所要做的就是新增一些大小調整、邊距等,使一切都看起來更漂亮,我們就完成了。
你會注意到標題段落已被賦予display: table-caption;,這使其像表格<caption>一樣,並且caption-side: bottom;告訴標題出於樣式目的位於表格底部,即使標記在原始碼中位於<input>元素之前。這允許一定的靈活性。
html {
font-family: sans-serif;
}
form {
display: table;
margin: 0 auto;
}
form div {
display: table-row;
}
form label,
form input {
display: table-cell;
margin-bottom: 10px;
}
form label {
width: 200px;
padding-right: 5%;
text-align: right;
}
form input {
width: 300px;
}
form p {
display: table-caption;
caption-side: bottom;
width: 300px;
color: #999;
font-style: italic;
}
這給了我們以下結果
你也可以在css-tables-example.html上檢視此示例(也請檢視原始碼)。
注意:與本頁的其他主題不同,表格佈局在本模組中不會進一步介紹。請改用網格佈局。
多列布局
多列布局 CSS 模組提供了一種將內容佈局成多列的方式,類似於報紙中文字的排列方式。雖然在網頁環境中上下閱讀多列內容由於使用者需要上下滾動而不太實用,但將內容排列成多列仍然可以是一種有用的技巧。
要將一個塊元素變成多列容器,我們可以使用 column-count 屬性,它告訴瀏覽器我們想要多少列,或者使用 column-width 屬性,它告訴瀏覽器用盡可能多的指定寬度的列填充容器。
在下面的示例中,我們從一個包含在具有 container 類的 <div> 元素中的 HTML 塊開始。
<div class="container">
<h1>Multi-column Layout</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus
aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci,
pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at
ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta.
</p>
<p>
Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada
ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed
est. Nam id risus quis ante semper consectetur eget aliquam lorem.
</p>
<p>
Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris
ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus
viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum
sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus
mus.
</p>
</div>
我們在這個容器上使用了 200 畫素的 column-width,導致瀏覽器建立儘可能多的 200 畫素寬的列。列之間剩餘的空間將被平均分配。
.container {
column-width: 200px;
}