定位

定位允许您将元素从正常的文档流中取出,并使其表现出不同的行为,例如,彼此叠加或始终保持在浏览器视口内的相同位置。本文介绍了不同的position值以及如何使用它们。

先决条件 HTML 基础知识(学习HTML 简介),以及 CSS 工作原理的概念(学习CSS 简介)。
目标 了解 CSS 定位的工作原理。

我们希望您在本地计算机上完成以下练习。如果可能,请从我们的 GitHub 仓库中获取0_basic-flow.html的副本(此处查看源代码),并将其作为起点。

介绍定位

定位允许我们通过覆盖正常的文档流来产生有趣的结果。如果您想稍微更改一些盒子的位置,使其偏离默认的流位置,以营造出略带古怪、破旧的感觉,该怎么办?定位就是您的工具。或者,如果您想创建一个 UI 元素,使其浮动在页面其他部分的顶部,并且/或者始终位于浏览器窗口内的相同位置,无论页面滚动多少,该怎么办?定位使这种布局工作成为可能。

您可以对 HTML 元素应用多种不同类型的定位。要使特定类型的定位对元素生效,我们使用position属性。

静态定位

要查看这一点(并为将来的部分设置示例),首先在 HTML 中的第二个<p>中添加一个名为 positionedclass

静态定位是每个元素都具有的默认值。它只是意味着“将元素放置到文档流中的正常位置——这里没有什么特别之处”。

html
<p class="positioned"></p>

现在将以下规则添加到 CSS 的底部

css
.positioned {
  position: static;
  background: yellow;
}

如果保存并刷新,您将看不到任何差异,除了更新了第二段的背景颜色。这很好——正如我们之前所说,静态定位是默认行为!

注意:您可以在1_static-positioning.html查看源代码)处查看此示例。

相对定位

相对定位是我们将要查看的第一种定位类型。这与静态定位非常相似,除了定位元素在正常流中占据其位置后,您可以修改其最终位置,包括使其与页面上的其他元素重叠。继续更新代码中的position声明

css
position: relative;

如果在此阶段保存并刷新,您将根本看不到结果发生变化。那么如何修改元素的位置呢?您需要使用topbottomleftright属性,我们将在下一节中解释这些属性。

介绍 top、bottom、left 和 right

topbottomleftrightposition一起使用,以精确指定将定位元素移动到哪里。要尝试此操作,请将以下声明添加到 CSS 中的.positioned规则中

css
top: 30px;
left: 30px;

注意:这些属性的值可以采用您合理期望的任何单位:像素、毫米、rem、% 等。

如果您现在保存并刷新,您将得到类似于以下的结果

很酷,是吗?好的,这可能不是您期望的结果。如果我们指定了topleft,为什么它会移动到底部和右侧?这可能看起来违反直觉。您需要将其视为一种无形的力量,它会推动定位框的指定边,使其向相反方向移动。例如,如果您指定top: 30px;,则就像一股力会推动框的顶部,导致它向下移动 30px。

注意:您可以在2_relative-positioning.html查看源代码)处查看此示例。

绝对定位

绝对定位会带来截然不同的结果。

设置 position: absolute

让我们尝试如下更改代码中的 position 声明

css
position: absolute;

如果您现在保存并刷新,您应该会看到如下所示的内容

首先,请注意,文档流中定位元素应该存在的间隙不再存在——第一个和第三个元素已经合在一起,就像它不再存在一样!好吧,从某种意义上说,这是真的。绝对定位的元素不再存在于正常的文档流中。相反,它位于自己的图层上,与其他所有内容分离。这非常有用:这意味着我们可以创建独立的 UI 功能,这些功能不会干扰页面上其他元素的布局。例如,弹出信息框、控制菜单、悬停面板、可以在页面上任何位置拖放的 UI 功能等等。

其次,请注意元素的位置已更改。这是因为topbottomleftright在绝对定位中具有不同的行为。它们不是根据元素在正常文档流中的相对位置来定位元素,而是指定元素距包含元素各边的距离。因此,在本例中,我们说绝对定位的元素应位于“包含元素”顶部 30px 处和左侧 30px 处。(在本例中,“包含元素”是初始包含块。有关更多信息,请参阅下面的部分)

注意:如果需要,您可以使用topbottomleftright来调整元素的大小。尝试在您的定位元素上设置top: 0; bottom: 0; left: 0; right: 0;margin: 0;,看看会发生什么!之后再放回去……

注意:是的,边距仍然会影响定位元素。但是,边距折叠不会。

注意:您可以在3_absolute-positioning.html查看源代码)处查看此示例。

定位上下文

绝对定位元素的“包含元素”是哪个元素?这在很大程度上取决于定位元素的祖先元素的 position 属性(请参阅确定包含块)。

如果祖先元素的 position 属性没有明确定义,则默认情况下所有祖先元素都将具有静态位置。其结果是绝对定位的元素将包含在初始包含块中。初始包含块具有视口的大小,也是包含<html>元素的块。换句话说,绝对定位的元素将显示在<html>元素之外,并相对于初始视口进行定位。

定位元素嵌套在 HTML 源代码中的<body>中,但在最终布局中,它距页面顶部和左侧边缘 30px。我们可以更改定位上下文,即绝对定位元素相对于哪个元素进行定位。这是通过在元素的某个祖先元素上设置定位来完成的:在它嵌套其中的某个元素上(您不能将其相对于它未嵌套其中的元素进行定位)。要查看这一点,请将以下声明添加到您的body规则中

css
position: relative;

这应该会产生以下结果

定位元素现在相对于<body>元素进行定位。

注意:您可以在4_positioning-context.html查看源代码)处查看此示例。

介绍 z-index

所有这些绝对定位都很有趣,但我们还没有考虑另一个功能。当元素开始重叠时,是什么决定了哪些元素出现在其他元素之上,哪些元素出现在其他元素之下?在我们到目前为止看到的示例中,我们只有一个定位上下文中的定位元素,并且它出现在顶部,因为定位元素优先于非定位元素。那么当我们有多个时呢?

尝试将以下内容添加到您的 CSS 中,使第一段也成为绝对定位的

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)规则中

css
z-index: 1;

您现在应该看到青柠色的段落位于顶部

请注意,z-index仅接受无单位的索引值;您不能指定希望一个元素在 Z 轴上向上移动 23 像素——它不这样工作。较高的值将位于较低值之上,使用什么值由您决定。使用 2 或 3 的值将与使用 300 或 40000 的值产生相同的效果。

注意:您可以在 5_z-index.html (查看源代码) 中查看此内容的示例。

固定定位

现在让我们来看一下固定定位。它的工作原理与绝对定位完全相同,但有一个关键区别:绝对定位将元素相对于其最近的已定位祖先(如果没有则为初始包含块)固定在适当位置,而固定定位通常将元素相对于视口可见部分固定在适当位置。(如果元素的祖先之一是固定包含块,因为其 transform 属性 的值不是 none,则会出现例外情况。)这意味着您可以创建有用的固定在适当位置的 UI 项目,例如始终可见的持久导航菜单,无论页面滚动多少。

让我们构建一个简单的示例来说明我们的意思。首先,从您的 CSS 中删除现有的 p:nth-of-type(1).positioned 规则。

现在更新 body 规则以删除 position: relative; 声明并添加一个固定高度,如下所示

css
body {
  width: 500px;
  height: 1400px;
  margin: 0 auto;
}

现在,我们将为 h1 元素添加 position: fixed; 并将其置于视口顶部。将以下规则添加到您的 CSS 中

css
h1 {
  position: fixed;
  top: 0;
  width: 500px;
  margin-top: 0;
  background: white;
  padding: 10px;
}

需要 top: 0; 使其粘贴到屏幕顶部。我们为标题赋予与内容列相同的宽度,然后赋予白色背景以及一些填充和边距,以便内容不会在其下方可见。

如果保存并刷新,您将看到标题保持固定的有趣效果——内容似乎向上滚动并在其下方消失。但是请注意,某些内容最初是如何在标题下被裁剪的。这是因为已定位的标题不再出现在文档流中,因此其余内容向上移动到顶部。我们可以通过将所有段落向下移动一点来改进这一点。我们可以通过在第一个段落上设置一些顶部边距来实现。现在添加此内容

css
p:nth-of-type(1) {
  margin-top: 60px;
}

您现在应该可以看到完成的示例

注意:您可以在 6_fixed-positioning.html (查看源代码) 中查看此内容的示例。

粘性定位

还有另一个可用的位置值称为 position: sticky,它比其他值更新一些。这基本上是相对定位和固定定位的混合体。它允许已定位的元素像相对定位一样工作,直到滚动到某个阈值(例如,距视口顶部 10px),然后它会变成固定定位。

基本示例

例如,可以使用粘性定位使导航栏随着页面滚动,直到某个点,然后粘贴到页面顶部。

css
.positioned {
  position: sticky;
  top: 30px;
  left: 30px;
}

滚动索引

position: sticky 的一个有趣且常见的用法是创建一个滚动索引页面,其中不同的标题在到达时会粘贴到页面顶部。此类示例的标记可能如下所示

html
<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 时,支持的浏览器会在标题到达该位置时将其粘贴到视口顶部。然后,每个后续标题在向上滚动到该位置时将替换上一个标题。

css
dt {
  background-color: black;
  color: white;
  padding: 10px;
  position: sticky;
  top: 0;
  left: 0;
  margin: 1em 0;
}

粘性元素相对于具有“滚动机制”的最近祖先而言是“粘性”的,这由其祖先的 overflow 属性决定。

注意:您可以在 7_sticky-positioning.html (查看源代码) 中查看此示例。

测试你的技能!

您已阅读完本文,但您还记得最重要的信息吗?在继续之前,您可以找到一些进一步的测试来验证您是否保留了这些信息——请参阅 测试您的技能:定位

总结

我相信您玩基本定位玩得很开心。虽然它不是用于整个布局的理想方法,但它适合许多特定的目标。

另请参阅