定位允许我们通过覆盖正常的文档流来产生有趣的结果。如果您想稍微改变一些盒子相对于其默认流位置的位置,以营造一种略显古怪、粗糙的感觉,定位就是您的工具。或者,如果您想创建一个浮动在页面其他部分上方和/或无论页面滚动多少都始终位于浏览器窗口中同一位置的 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 属性决定。
我相信您在玩基本定位时玩得很开心。虽然它不是用于整个布局的理想方法,但它适用于许多特定的目标。
在下一篇文章中,我们将为您提供一些测试,您可以使用它们来检查您对所有这些信息的理解和掌握程度。