定位允許我們透過覆蓋正常的文件流來產生有趣的結果。如果您想稍微改變一些盒子相對於其預設流位置的位置,以營造一種略顯古怪、粗糙的感覺,定位就是您的工具。或者,如果您想建立一個浮動在頁面其他部分上方和/或無論頁面滾動多少都始終位於瀏覽器視窗中同一位置的 UI 元素,定位使得此類佈局工作成為可能。
有多種不同型別的定位可以應用於 HTML 元素。要使特定型別的定位在元素上生效,我們使用 position 屬性。
靜態定位是每個元素都會得到的預設值。它只是意味著“將元素放置在其在正常流中的預設位置——沒有什麼特別的。”
要檢視此內容(併為將來的部分設定示例),首先將一個 class 為 positioned 新增到 HTML 中的第二個 <p> 元素中
<p class="positioned">…</p>
現在將以下規則新增到您的 CSS 底部
.positioned {
position: static;
background: yellow;
}
如果您儲存並重新整理,除了第二個段落的背景顏色更新外,您將看不到任何區別。這很好——正如我們之前所說,靜態定位是預設行為!
相對定位是我們首先要看的一種定位型別。這與靜態定位非常相似,不同之處在於,一旦定位元素在正常流中佔據了位置,您就可以修改其最終位置,包括使其與頁面上的其他元素重疊。繼續並在您的程式碼中更新 position 宣告
如果在此階段儲存並重新整理,結果將不會有任何變化。那麼如何修改元素的位置呢?您需要使用 top、bottom、left 和 right 屬性,我們將在下一節中解釋。
top、bottom、left 和 right 與 position 結合使用,以精確指定定位元素要移動到的位置。要嘗試此操作,請將以下宣告新增到 CSS 中的 .positioned 規則中
注意: 這些屬性的值可以採用您合理期望的任何 單位:畫素、毫米、rem、百分比等。
如果您現在儲存並重新整理,您將得到類似這樣的結果
<h1>Relative positioning</h1>
<p>
I am a basic block level element. My adjacent block level elements sit on new
lines below me.
</p>
<p class="positioned">
By default we span 100% of the width of our parent element, and we are as tall
as our child content. Our total width and height is our content + padding +
border width/height.
</p>
<p>
We are separated by our margins. Because of margin collapsing, we are
separated by the width of one of our margins, not both.
</p>
<p>
Inline elements <span>like this one</span> and <span>this one</span> sit on
the same line as one another, and adjacent text nodes, if there is space on
the same line. Overflowing inline elements
<span>wrap onto a new line if possible — like this one containing text</span>,
or just go on to a new line if not, much like this image will do:
<img
src="https://mdn.github.io/shared-assets/images/examples/long.jpg"
alt="snippet of cloth" />
</p>
body {
width: 500px;
margin: 0 auto;
}
p {
background: aqua;
border: 3px solid blue;
padding: 10px;
margin: 10px;
}
span {
background: red;
border: 1px solid black;
}
.positioned {
position: relative;
background: yellow;
top: 30px;
left: 30px;
}
很酷,是吧?好吧,這可能不是您所期望的。如果我們指定了 *top* 和 *left*,為什麼它會向底部和向右移動?這可能看起來違反直覺。您需要將其視為有一種無形的力量推動定位框的指定側,使其向相反方向移動。例如,如果您指定 top: 30px;,就好像有一種力量會推動框的頂部,使其向下移動 30px。
讓我們嘗試按如下方式更改程式碼中的 position 宣告
如果您現在儲存並重新整理,您應該會看到類似這樣的內容
<h1>Absolute positioning</h1>
<p>
I am a basic block level element. My adjacent block level elements sit on new
lines below me.
</p>
<p class="positioned">
By default we span 100% of the width of our parent element, and we are as tall
as our child content. Our total width and height is our content + padding +
border width/height.
</p>
<p>
We are separated by our margins. Because of margin collapsing, we are
separated by the width of one of our margins, not both.
</p>
<p>
inline elements <span>like this one</span> and <span>this one</span> sit on
the same line as one another, and adjacent text nodes, if there is space on
the same line. Overflowing inline elements
<span>wrap onto a new line if possible — like this one containing text</span>,
or just go on to a new line if not, much like this image will do:
<img
src="https://mdn.github.io/shared-assets/images/examples/long.jpg"
alt="snippet of cloth" />
</p>
body {
width: 500px;
margin: 0 auto;
}
p {
background: aqua;
border: 3px solid blue;
padding: 10px;
margin: 10px;
}
span {
background: red;
border: 1px solid black;
}
.positioned {
position: absolute;
background: yellow;
top: 30px;
left: 30px;
}
首先,請注意定位元素在文件流中應有的空白處已不復存在——第一個和第三個元素已經關閉在一起,就像它不再存在一樣!從某種意義上說,這是真的。絕對定位的元素不再存在於正常的文件流中。相反,它位於自己的層中,獨立於所有其他元素。這非常有用:這意味著我們可以建立獨立的 UI 功能,而不會干擾頁面上其他元素的佈局。例如,彈出資訊框、控制選單、懸停面板、可以在頁面上隨意拖放的 UI 功能等等。
其次,請注意元素的位置已更改。這是因為 top、bottom、left 和 right 在絕對定位中以不同的方式表現。它們不是基於元素在正常文件流中的相對位置來定位元素,而是指定元素與包含元素各邊的距離。在這種情況下,我們說絕對定位的元素應該距離**包含元素**(在本例中是**初始包含塊**,見下文)頂部 30px,距離左側 30px。
注意: 如果需要,您可以使用 top、bottom、left 和 right 來調整元素大小。嘗試在您的定位元素上設定 top: 0; bottom: 0; left: 0; right: 0; 和 margin: 0;,看看會發生什麼!之後再將其改回來……
注意: 是的,外邊距仍然會影響定位元素。但是,外邊距摺疊不會。
絕對定位元素的“包含元素”是哪個元素?這在很大程度上取決於定位元素祖先的 position 屬性值。
如果沒有祖先元素明確定義了它們的 position 屬性,那麼預設情況下所有祖先元素都將具有靜態位置。這樣做的結果是絕對定位元素將被包含在**初始包含塊**中。初始包含塊具有視口的尺寸,也是包含 <html> 元素的塊。換句話說,絕對定位元素將顯示在 <html> 元素之外,並相對於初始視口定位。
定位元素巢狀在 HTML 源中的 <body> 內部,但在最終佈局中,它距離頁面頂部和左邊緣 30px。我們可以更改**定位上下文**,即絕對定位元素相對於哪個元素進行定位。這可以透過在其祖先元素之一上設定定位來實現:它可以巢狀在其中的一個元素(不能相對於它不巢狀在其中的元素進行定位)。要檢視此內容,請將以下宣告新增到您的 body 規則中
這應該會得到以下結果
<h1>Positioning context</h1>
<p>
I am a basic block level element. My adjacent block level elements sit on new
lines below me.
</p>
<p class="positioned">
Now I'm absolutely positioned relative to the
<code><body></code> element, not the <code><html></code> element!
</p>
<p>
We are separated by our margins. Because of margin collapsing, we are
separated by the width of one of our margins, not both.
</p>
<p>
inline elements <span>like this one</span> and <span>this one</span> sit on
the same line as one another, and adjacent text nodes, if there is space on
the same line. Overflowing inline elements
<span>wrap onto a new line if possible — like this one containing text</span>,
or just go on to a new line if not, much like this image will do:
<img
src="https://mdn.github.io/shared-assets/images/examples/long.jpg"
alt="snippet of cloth" />
</p>
body {
width: 500px;
margin: 0 auto;
position: relative;
}
p {
background: aqua;
border: 3px solid blue;
padding: 10px;
margin: 10px;
}
span {
background: red;
border: 1px solid black;
}
.positioned {
position: absolute;
background: yellow;
top: 30px;
left: 30px;
}
定位元素現在相對於 <body> 元素。
所有這些絕對定位都很有趣,但我們還有一個尚未考慮的功能。當元素開始重疊時,什麼決定了哪些元素出現在其他元素之上,哪些元素出現在其他元素之下?到目前為止,我們看到的示例中,定位上下文中只有一個定位元素,它出現在頂部,因為定位元素優先於非定位元素。那麼當我們有多個定位元素時會怎樣呢?
嘗試將以下內容新增到您的 CSS 中,使第一個段落也絕對定位
p:nth-of-type(1) {
position: absolute;
background: lime;
top: 10px;
right: 30px;
}
此時您會看到第一個段落顯示為石灰色,移出了文件流,並定位在它原來位置的稍上方。當兩者重疊時,它也堆疊在原始的 .positioned 段落下方。這是因為 .positioned 段落是原始碼順序中的第二個段落,而原始碼順序中靠後的定位元素會優先於原始碼順序中靠前的定位元素。
你能改變堆疊順序嗎?是的,你可以,透過使用 z-index 屬性。“z-index”指的是 z 軸。你可能還記得在本課程之前的章節中我們討論過網頁使用水平(x 軸)和垂直(y 軸)座標來確定背景圖片和陰影偏移等元素的定位。對於從左到右的語言,(0,0) 位於頁面的左上角(或元素),x 和 y 軸向右和向下延伸。
網頁也有一個 z 軸:一條假想的線,從螢幕表面延伸到您的臉部(或您喜歡放在螢幕前的任何其他東西)。 z-index 值影響定位元素在該軸上的位置;正值將它們向上移動,負值將它們向下移動。預設情況下,所有定位元素的 z-index 都是 auto,這實際上是 0。
要改變堆疊順序,嘗試將以下宣告新增到您的 p:nth-of-type(1) 規則中
您現在應該會看到石灰色的段落在頂部
<h1>z-index</h1>
<p>
I am a basic block level element. My adjacent block level elements sit on new
lines below me.
</p>
<p class="positioned">
Now I'm absolutely positioned relative to the
<code><body></code> element, not the <code><html></code> element!
</p>
<p>
We are separated by our margins. Because of margin collapsing, we are
separated by the width of one of our margins, not both.
</p>
<p>
inline elements <span>like this one</span> and <span>this one</span> sit on
the same line as one another, and adjacent text nodes, if there is space on
the same line. Overflowing inline elements
<span>wrap onto a new line if possible — like this one containing text</span>,
or just go on to a new line if not, much like this image will do:
<img
src="https://mdn.github.io/shared-assets/images/examples/long.jpg"
alt="snippet of cloth" />
</p>
body {
width: 500px;
margin: 0 auto;
position: relative;
}
p {
background: aqua;
border: 3px solid blue;
padding: 10px;
margin: 10px;
}
span {
background: red;
border: 1px solid black;
}
.positioned {
position: absolute;
background: yellow;
top: 30px;
left: 30px;
}
p:nth-of-type(1) {
position: absolute;
background: lime;
top: 10px;
right: 30px;
z-index: 1;
}
請注意,z-index 只接受無單位的索引值;你不能指定你想要一個元素在 Z 軸上向上 23 畫素——它不是那樣工作的。更高的值會高於更低的值,至於你使用什麼值則由你決定。使用 2 或 3 的值會產生與 300 或 40000 的值相同的效果。
現在我們來看固定定位。它的工作方式與絕對定位完全相同,只有一個關鍵區別:絕對定位將元素固定在相對於其最近的定位祖先(如果沒有,則為初始包含塊)的位置,而**固定定位**將元素固定在相對於視口的可見部分的位置。這意味著您可以建立固定在位的有用 UI 元素,例如無論頁面滾動多少都始終可見的持久導航選單。
讓我們來做一個簡單的例子,展示我們的意思。首先,從 CSS 中刪除現有的 p:nth-of-type(1) 和 .positioned 規則。
現在更新 body 規則以刪除 position: relative; 宣告並新增一個固定高度,如下所示
body {
width: 500px;
height: 1400px;
margin: 0 auto;
}
現在我們將給 <h1> 元素設定 position: fixed; 並讓它位於視口的頂部。將以下規則新增到您的 CSS 中
h1 {
position: fixed;
top: 0;
width: 500px;
margin-top: 0;
background: white;
padding: 10px;
}
top: 0; 是使其固定在螢幕頂部所必需的。我們將標題設定為與內容列相同的寬度,然後新增白色背景、一些內邊距和外邊距,這樣內容就不會在標題下方可見。
如果您儲存並重新整理,您將看到一個有趣的小效果:標題保持固定不動——內容似乎向上滾動並消失在標題下方。但請注意,有些內容最初被標題遮蓋了。這是因為定位的標題不再出現在文件流中,因此其餘內容向上移動。我們可以透過將所有段落稍微向下移動一點來改善這一點。現在新增以下內容
p:nth-of-type(1) {
margin-top: 60px;
}
您現在應該看到完成的示例
<h1>Fixed positioning</h1>
<p>
I am a basic block level element. My adjacent block level elements sit on new
lines below me.
</p>
<p class="positioned">I'm not positioned any more.</p>
<p>
We are separated by our margins. Because of margin collapsing, we are
separated by the width of one of our margins, not both.
</p>
<p>
Inline elements <span>like this one</span> and <span>this one</span> sit on
the same line as one another, and adjacent text nodes, if there is space on
the same line. Overflowing inline elements
<span>wrap onto a new line if possible — like this one containing text</span>,
or just go on to a new line if not, much like this image will do:
<img
src="https://mdn.github.io/shared-assets/images/examples/long.jpg"
alt="snippet of cloth" />
</p>
body {
width: 500px;
height: 1400px;
margin: 0 auto;
}
p {
background: aqua;
border: 3px solid blue;
padding: 10px;
margin: 10px;
}
span {
background: red;
border: 1px solid black;
}
h1 {
position: fixed;
top: 0px;
width: 500px;
background: white;
padding: 10px;
}
p:nth-of-type(1) {
margin-top: 60px;
}
還有另一個可用的 position 值,叫做 position: sticky,它比其他的要新一些。這基本上是相對定位和固定定位的混合體。它允許定位元素在滾動到某個閾值(例如,距離視口頂部 10px)之前表現得像相對定位一樣,之後它就變為固定定位。
粘性定位可以用於,例如,使導航欄隨著頁面滾動到某個點,然後固定在頁面頂部。
<h1>Sticky positioning</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. 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>
<div class="positioned">Sticky</div>
<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. 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>
<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>
body {
width: 500px;
margin: 0 auto;
}
.positioned {
background: rgb(255 84 104 / 30%);
border: 2px solid rgb(255 84 104);
padding: 10px;
margin: 10px;
border-radius: 5px;
}
.positioned {
position: sticky;
top: 30px;
left: 30px;
}
position: sticky 的一個有趣且常見的用途是建立滾動索引頁面,其中不同的標題在到達頁面頂部時會固定在那裡。此類示例的標記可能如下所示
<h1>Sticky positioning</h1>
<dl>
<dt>A</dt>
<dd>Apple</dd>
<dd>Ant</dd>
<dd>Altimeter</dd>
<dd>Airplane</dd>
<dt>B</dt>
<dd>Bird</dd>
<dd>Buzzard</dd>
<dd>Bee</dd>
<dd>Banana</dd>
<dd>Beanstalk</dd>
<dt>C</dt>
<dd>Calculator</dd>
<dd>Cane</dd>
<dd>Camera</dd>
<dd>Camel</dd>
<dt>D</dt>
<dd>Duck</dd>
<dd>Dime</dd>
<dd>Dipstick</dd>
<dd>Drone</dd>
<dt>E</dt>
<dd>Egg</dd>
<dd>Elephant</dd>
<dd>Egret</dd>
</dl>
CSS 可能如下所示。在正常流中,<dt> 元素將隨內容滾動。當我們為 <dt> 元素新增 position: sticky,並設定 top 值為 0 時,支援的瀏覽器會在標題到達該位置時將其固定在視口頂部。每個後續標題在滾動到該位置時將替換前一個標題。
dt {
background-color: black;
color: white;
padding: 10px;
position: sticky;
top: 0;
left: 0;
margin: 1em 0;
}
body {
width: 500px;
height: 880px;
margin: 0 auto;
}
粘性元素相對於最近的具有“滾動機制”的祖先元素“粘性”,該機制由其祖先的 overflow 屬性決定。
我相信您在玩基本定位時玩得很開心。雖然它不是用於整個佈局的理想方法,但它適用於許多特定的目標。
在下一篇文章中,我們將為您提供一些測試,您可以使用它們來檢查您對所有這些資訊的理解和掌握程度。