Menu

CSS position 定位:absolute、relative、fixed 与 sticky

position: absolute 把元素放在最近的已定位祖先元素内部的精确坐标上。本文讲解 absolute 如何配合 position: relative 使用,然后介绍 fixed 和 sticky、top/right/bottom/left 和 inset 属性,以及 sticky 有时为什么粘不住。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

一个例子看懂 position: absolute

绝对定位的元素会被移出常规流,并用 top、right、bottom 和 left 来放置。这些偏移量从最近的、position 不是 static 的祖先元素开始计算,所以父元素要设置 position: relative:

把 .card 上的 position: relative 删掉,徽标就会跳到整个页面的右上角,因为它不再有已定位的祖先元素。大多数“position absolute 不生效”的问题,都可以用这一行来解释。

关于绝对定位元素,你需要知道:

  • 它们不占空间。 标题和段落的排版就像徽标不存在一样。
  • 它们的宽度会收缩到刚好包住内容,除非你设置了 width,或者同时设置了 left 和 right。
  • 偏移量相对于包含块的内边距边缘计算,也就是在它的边框内侧。

position 的五个值

值是否在常规流中?偏移量的参照典型用途
static(默认值)是忽略偏移量普通元素
relative是,保留原有空间它自己的正常位置作为绝对定位子元素的参照,微调位置
absolute否最近的已定位祖先元素(或页面)徽标、提示框、遮罩层、关闭按钮
fixed否视口头部导航、聊天按钮、Cookie 提示条
sticky是到达偏移位置后,相对于它的滚动容器表头、章节标题、侧边栏

position: relative

相对定位的元素保留它在常规流中的位置。偏移量会移动它的绘制位置,但原来的空间仍然被保留,所以它周围的元素都不会移动:

盒子 2 被向下、向右各移动了 20px 来绘制,盖住了盒子 3,但盒子 3 并没有移动:它仍然在原来的位置给盒子 2 留着空间。单独使用时,relative 很少用来移动元素;它的主要作用是充当绝对定位子元素的参照盒。

偏移量与 inset

top、right、bottom 和 left 可以取长度、百分比(相对于包含块)和 auto。inset 简写按照和 margin 相同的顺序设置这四个值:

.overlay {
  position: absolute;
  inset: 0;              /* top: 0; right: 0; bottom: 0; left: 0; */
}
.corner {
  position: absolute;
  inset: auto 16px 16px auto;  /* bottom right corner, 16px in */
}

同时设置相对的两边会把元素拉伸:left: 0; right: 0 让它和包含块一样宽。在绝对定位的子元素上设置 inset: 0,是用遮罩层盖住整张卡片的标准做法。

用 absolute 和 transform 居中

top: 50%; left: 50% 把元素的左上角放在中心点。然后 translate(-50%, -50%) 再把它往回移动自身尺寸的一半:

如果元素可以留在常规流中,用 flexbox 和 grid 居中会更简单;div 居中页面比较了所有方法。

position: fixed

固定定位的元素相对于视口放置,页面滚动时它保持不动:

.chat-button {
  position: fixed;
  bottom: 16px;
  right: 16px;
}

有两个坑。固定定位的元素不占空间,所以固定的头部会盖住页面顶部,除非你给 body 加上 padding-top。另外,如果任何祖先元素设置了 transform、filter 或 perspective,参照盒就会变成那个祖先元素而不是视口,于是元素会跟着它一起滚动。

position: sticky

粘性定位的元素会正常滚动,直到到达偏移位置,然后粘在那里,直到它的父元素末尾滚动过去。滚动下面的盒子试试:

每个字母在它所在的部分可见时都会粘在滚动盒的顶部,然后被下一个字母推走,因为 sticky 元素永远不会离开它的父元素。

如果 sticky 粘不住,检查以下几点:

  • 没有偏移量。 没有 top、bottom、left 或 right 时,position: sticky 不起作用。
  • 某个祖先元素设置了 overflow: hidden、auto 或 scroll。 它会成为滚动容器,如果它实际上并不滚动,就什么都粘不住。如果你只是想隐藏溢出内容,请使用 overflow: clip。
  • 父元素并不比 sticky 元素高。 在它内部没有可以粘住的空间。
  • flex 或 grid 父元素把它拉伸了。 在 flex 行中,给粘性侧边栏加上 align-self: flex-start。

常见错误

  • 忘了给绝对定位元素的父元素设置 position: relative。
  • 用 absolute 做页面布局。 绝对定位的元素彼此之间、与内容之间互不理会,在小屏幕上文字就会重叠。布局用 flexbox 或 grid,absolute 只用来做小装饰。
  • 给 static 元素设置偏移量。 没有 position 时,top: 10px 不起作用。
  • 为谁显示在最上层而纠结。 重叠的已定位元素按 z-index 排序。
  • 固定头部遮住了内容。 给页面加上内边距,或者设置 scroll-padding-top,让锚点链接跳转后落在头部下方。

常见问题

position: absolute 有什么作用?

它把元素移出常规流(其他元素表现得就像它不存在一样),并用 top、right、bottom 和 left 来放置它,这些偏移量相对于它的包含块计算:即最近的、position 不是 static 的祖先元素。

如何让元素相对于父元素进行绝对定位?

给父元素设置 position: relative;,给子元素设置 position: absolute; 并加上偏移量,例如 top: 0; right: 0;。如果没有已定位的父元素,子元素会相对于页面定位。

相对定位和绝对定位有什么区别?

relative 让元素留在常规流中,只改变它的绘制位置,原来的空间仍然保留。absolute 把元素移出常规流,并相对于已定位的祖先元素放置它。

为什么 position: sticky 不生效?

通常是以下三种原因之一:没有设置 top(或其他偏移量);某个祖先元素设置了 overflow: hidden 或 auto,成了滚动容器;或者 sticky 元素的父元素并不比它高,没有可以粘住的空间。

fixed 和 sticky 有什么区别?

fixed 会被移出常规流,并固定在视口上(除非某个祖先元素设置了 transform 或 filter)。sticky 留在常规流中,正常滚动,直到到达它的偏移位置,然后在父元素仍在屏幕上时一直粘在那里。

Coddy 编程语言插图

和 Coddy 一起学编程

开始