JobbyM's Blog

一日一练-CSS 了解Positioning

名词解释

Positioning:定位

什么是 Positioning

Positioning 允许你从正常的文档流布局中取出元素,并使它们具有不同的行为,例如放在另个一个元素的上面,或者始终保持在浏览器视窗内的同一位置。其实就是定位(position)的各种不同值,以及如何使用它们。

文档流

定位是一个相当复杂的话题,所以我们深入了解代码之前,让我们审视一下布局理论,并让我们了解它的工作原理。

首先,围绕元素内容添加任何内边距、边界和外边距来布置单个元素盒子–这就是盒模型。默认情况下,块级元素的内容宽度是其父元素的宽度的 100%,并且与其内容一样高。内联元素高宽与他们的内容高宽一样。你不能对内联永远是设置宽度或高度–它们只是位于块级元素的内容中。如果要以这种方式控制内联元素的大小,则需要将其设置为类似块级元素display: block;

这只是解释了单个元素,但是元素之间如何交互呢? 正常布局流 是将元素放置在浏览器视口内。默认情况下,块级元素在视口中垂直布局–每个都将显示在上一个元素下面的新行上,并且他们的外边距分割开他们。

内联元素表现不一样–他们不会出现在新行上;相反,他们相互之间以及任何相邻(或被包裹)的文本内容位于同一行上,只要在父块级元素的宽度内有空间可以这样做。如果没有空间,那么溢流的文本或元素将向下移动到新行。

如果两个相邻元素都在其上设置外边距,并且两个外边距接触,则两个外边距中的较大者保留,较小的一个消失–这叫外边距折叠。

介绍定位

静态定位

静态定位是每个元素获取的默认值——它只是意味着“将元素放入它在文档布局流中的正常位置 ——这里没有什么特别的。

1
2
3
.positioned {
position: static;
}

相对定位

相对定位是我们将要看的第一个位置类型。 它与静态定位非常相似,占据在正常的文档流中,除了你仍然可以修改它的最终位置,包括让它与页面上的其他元素重叠。

1
2
3
.positioned {
position: relative;
}

使用 top, bottom, leftright 来精确指定要将定位元素移动到的位置。

绝对定位

绝对定位带来了非常不同的结果

1
2
3
.positioned {
position: absolute;
}

首先,绝对定位的元素不再存在于正常文档布局流中。相反,它坐在它自己的层独立于一切。这是非常有用的:这意味着我们可以创建不干扰页面上其他元素的位置的隔离的UI功能 。例如,弹出信息框和控制菜单;翻转面板;可以在页面上的任何地方拖放的UI功能……

第二,注意元素的位置已经改变——这是因为top, bottom, leftright 以不同的方式在绝对定位。 它们指定元素应距离每个包含元素的边的距离,而不是指定元素应该移入的方向。

注意:是的,margins 仍会影响定位的元素。 然而margin collapsing不会。

定位上下文

哪个元素是绝对定位元素的“包含元素“?这取决于绝对定位元素的父元素的 position 属性。参考Identifying the containing block

如果所有的父元素都没有显式地定义 position 属性,那么所有的父元素默认情况下 position 属性都是 static。结果,绝对定位元素会被包含在初始块容器中。这个初始块容器有着和浏览器视口一样的尺寸,并且 <html> 元素也被包含在这个容器里面。简单来说,绝对定位元素会被放在 <html> 元素的外面,并且根据浏览器视口来定位。

绝对定位元素在 HTML 源代码中,是被放在 <body> 中的,但是在最终的布局里面,它离页面(而不是 <body> )的左边界、上边界有 30px 的距离。我们可以改变定位上下文 —— 绝对定位的元素的相对位置元素。通过设置其中一个父元素的定位属性 —— 也就是包含绝对定位元素的那个元素(如果要设置绝对定位元素的相对元素,那么这个元素一定要包含绝对定位元素)。

介绍 z-index

所有这些绝对定位很有趣,但还有另一件事我们还没有考虑到 ——当元素开始重叠,什么决定哪些元素出现在其他元素的顶部? 在我们已经看到的示例中,我们在定位上下文中只有一个定位的元素,它出现在顶部,因为定位的元素胜过未定位的元素。 当我们有不止一个的时候呢?

尝试添加以下到你的CSS,使第一段也是绝对定位:

1
2
3
4
5
6
p:nth-of-type(1) {
position: absolute;
background: lime;
top: 10px;
right: 30px;
}

此时,你将看到第一段的颜色为绿色,移出文档流程,并位于原始位置上方一点。它也堆叠在原始的 .positioned 段落下,其中两个重叠。这是因为 .positioned 段落是源顺序(HTML标记)中的第二个段落,并且源顺序中后定位的元素将赢得先定位的元素。

你可以更改堆叠顺序吗?是的,你可以使用 z-index 属性。 z-index 是对 z 轴的参考。你可以从源代码中的上一点回想一下,我们使用水平(x轴)和垂直(y轴)坐标来讨论网页,以确定像背景图像和阴影偏移之类的东西的位置。 (0,0)位于页面(或元素)的左上角,x 和 y 轴跨页面向右和向下(适合从左到右的语言,无论如何)。

网页也有一个 z 轴:一条从屏幕表面到你的脸(或者在屏幕前面你喜欢的任何其他东西)的虚线。z-index 值影响定位元素位于该轴上的位置;正值将它们移动到堆栈上方,负值将它们向下移动到堆栈中。默认情况下,定位的元素都具有 z-index 为 auto,实际上为 0。

请注意,z-index 只接受无单位索引值;你不能指定你想要一个元素是 Z 轴上 23 像素—— 它不这样工作。

固定定位

还有一种类型的定位覆盖——fixed。 这与绝对定位的工作方式完全相同,只有一个主要区别:绝对定位固定元素是相对于 <html> 元素或其最近的定位祖先,而固定定位固定元素则是相对于浏览器视口本身。 这意味着您可以创建固定的有用的 UI 项目,如持久导航菜单。

position: sticky

还有一个可用的位置值称为 position: sticky;,比起其他位置值要新一些。它基本上是相对位置和固定位置的混合体,它允许被定位的元素表现得像相对定位一样,直到它滚动到某个阈值点(例如,从视口顶部起1​​0像素)为止,此后它就变得固定了。例如,它可用于使导航栏随页面滚动直到特定点,然后粘贴在页面顶部。

1
2
3
4
5
.positioned {
position: sticky;
top: 30px;
left: 30px;
}

position: sticky; 的另一种有趣且常用的用法,是创建一个滚动索引页面。在此页面上,不同的标题会停留在页面顶部。这样的标记可能如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<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,当标题滚动到视口的顶部时,支持此属性的浏览器会将标题粘贴到那个位置。随后,每个后续标题将替换前一个标题,知道它向上滚动到该位置。

1
2
3
4
5
6
7
8
9
dt {
background-color: black;
color: white;
padding: 10px;
position: sticky;
top: 0;
left: 0;
margin: 1em 0;
}

参考文档

1.MDN Learning Arae
2.MDN 学习 Web 开发-CSS-CSS 布局-定位