Skip to content

CSS 定位与层叠

CSS 定位让你可以将元素从正常的文档流中取出,放置到页面的任意位置。从固定的导航栏到弹出的模态框,定位是实现这些常见 UI 模式的关键技术。

position 属性#

position 属性决定了元素的定位方式,有五个可选值:

static(默认值)#

static 是默认值,元素按照正常的文档流排列:

.box {
position: static; /* 默认值,通常不需要显式设置 */
}

static 定位的元素不受 toprightbottomleftz-index 属性的影响。

relative(相对定位)#

相对定位让元素相对于自身原本的位置进行偏移:

.box {
position: relative;
top: 20px;
left: 30px;
}

🎯 关键特点:

  1. 元素仍然占据原来的空间(不脱离文档流)
  2. 偏移是相对于元素原本的位置
  3. 常用作绝对定位元素的参照容器
<div class="container">
<div class="box">我向右下偏移了,但原位置仍被保留</div>
<div class="sibling">我不会填补上面元素的位置</div>
</div>
.box {
position: relative;
top: 20px;
left: 20px;
background: #3b82f6;
}
.sibling {
background: #10b981;
/* 不会向上移动填补空间 */
}

absolute(绝对定位)#

绝对定位让元素相对于最近的已定位祖先元素进行定位:

.parent {
position: relative; /* 成为定位参照 */
}
.child {
position: absolute;
top: 0;
right: 0;
}

🎯 关键特点:

  1. 元素脱离文档流,不再占据空间
  2. 相对于最近的 position 不为 static 的祖先定位
  3. 如果没有已定位的祖先,则相对于初始包含块(通常是视口)
<div class="card">
<span class="badge">热门</span>
<h3>商品标题</h3>
</div>
.card {
position: relative;
padding: 1rem;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
.badge {
position: absolute;
top: -8px;
right: -8px;
padding: 0.25rem 0.5rem;
background: #ef4444;
color: white;
font-size: 0.75rem;
border-radius: 4px;
}

fixed(固定定位)#

固定定位让元素相对于视口进行定位,滚动页面时元素位置不变:

.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 60px;
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 100;
}
/* 为 fixed 导航预留空间 */
body {
padding-top: 60px;
}

固定定位也脱离文档流。常见用途:

/* 回到顶部按钮 */
.back-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 48px;
height: 48px;
border-radius: 50%;
background: #3b82f6;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}

🔶 注意:如果祖先元素设置了 transformperspectivefilter 属性,fixed 定位会相对于该祖先而非视口。

sticky(粘性定位)#

粘性定位是 relative 和 fixed 的混合体。元素在滚动到特定位置之前表现为相对定位,之后表现为固定定位:

.section-header {
position: sticky;
top: 0;
background: white;
padding: 1rem;
border-bottom: 1px solid #e5e7eb;
}

🎯 粘性定位的触发条件:

  1. 必须指定 toprightbottomleft 中的至少一个
  2. 父元素不能设置 overflow: hiddenoverflow: auto
  3. 父元素必须有足够的高度
<div class="contact-list">
<div class="letter-group">
<h3 class="letter">A</h3>
<ul>
<li>Alice</li>
<li>Amanda</li>
</ul>
</div>
<div class="letter-group">
<h3 class="letter">B</h3>
<ul>
<li>Bob</li>
<li>Brian</li>
</ul>
</div>
</div>
.letter {
position: sticky;
top: 0;
background: #f3f4f6;
padding: 0.5rem 1rem;
margin: 0;
}

定位偏移属性#

toprightbottomleft 用于设置定位元素的偏移量:

.box {
position: absolute;
top: 20px; /* 距离参照顶部 20px */
left: 30px; /* 距离参照左侧 30px */
}

拉伸填满#

同时设置对立方向的偏移可以拉伸元素:

/* 填满整个容器 */
.overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* 等效于 inset: 0; */
}
/* 只填充宽度 */
.full-width {
position: absolute;
left: 0;
right: 0;
}

inset 简写#

insettoprightbottomleft 的简写:

.overlay {
position: absolute;
inset: 0; /* top: 0; right: 0; bottom: 0; left: 0; */
}
.box {
position: absolute;
inset: 10px 20px; /* top/bottom: 10px; left/right: 20px; */
}
.box {
position: absolute;
inset: 10px 20px 30px 40px; /* 上 右 下 左 */
}

居中定位#

经典的绝对定位居中方法:

/* 方法 1:负 margin(需要知道元素尺寸) */
.centered {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 100px;
margin-top: -50px; /* 高度的一半 */
margin-left: -100px; /* 宽度的一半 */
}
/* 方法 2:transform(无需知道尺寸,推荐) */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* 方法 3:inset + margin auto */
.centered {
position: absolute;
inset: 0;
width: 200px;
height: 100px;
margin: auto;
}

z-index 与层叠#

当定位元素重叠时,z-index 决定谁在上面。

基本用法#

.box1 {
position: relative;
z-index: 1;
}
.box2 {
position: relative;
z-index: 2; /* 在 box1 上面 */
}

🔶 z-index 只对定位元素(position 不为 static)有效。

层叠上下文#

🎯 理解层叠上下文是掌握 z-index 的关键。

层叠上下文是一个三维概念,决定了元素在 Z 轴上的排列顺序。以下情况会创建新的层叠上下文:

/* 创建新的层叠上下文 */
.new-context {
position: relative;
z-index: 0; /* 或任何非 auto 值 */
}
/* 也会创建层叠上下文 */
.another-context {
opacity: 0.99;
}

层叠顺序#

在同一个层叠上下文内,元素的层叠顺序(从下到上):

  1. 层叠上下文的背景和边框
  2. z-index 为负值的定位元素
  3. 非定位的块级元素
  4. 浮动元素
  5. 非定位的行内元素
  6. z-index: 0z-index: auto 的定位元素
  7. z-index 为正值的定位元素

常见陷阱#

🙋 为什么我的 z-index: 9999 不起作用?

<div class="parent1">
<div class="child1">z-index: 9999</div>
</div>
<div class="parent2">
<div class="child2">z-index: 1</div>
</div>
.parent1 {
position: relative;
z-index: 1;
}
.child1 {
position: relative;
z-index: 9999; /* 看起来很大,但... */
}
.parent2 {
position: relative;
z-index: 2; /* parent2 在 parent1 上面 */
}
.child2 {
position: relative;
z-index: 1; /* child2 也在 child1 上面! */
}

原因:z-index 只在同一层叠上下文内比较。child1child2 在不同的层叠上下文中,它们的层叠顺序由父元素决定。

解决方案:管理好层叠上下文的层级,建立统一的 z-index 规范:

:root {
--z-dropdown: 100;
--z-sticky: 200;
--z-fixed: 300;
--z-modal-backdrop: 400;
--z-modal: 500;
--z-popover: 600;
--z-tooltip: 700;
}

实战案例#

模态框#

/* 遮罩层 */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: var(--z-modal-backdrop, 400);
}
/* 模态框 */
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
max-width: 500px;
max-height: 90vh;
background: white;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
z-index: var(--z-modal, 500);
overflow: auto;
}
.modal-header {
position: sticky;
top: 0;
padding: 1rem 1.5rem;
background: white;
border-bottom: 1px solid #e5e7eb;
}
.modal-body {
padding: 1.5rem;
}
.modal-footer {
position: sticky;
bottom: 0;
padding: 1rem 1.5rem;
background: white;
border-top: 1px solid #e5e7eb;
}

下拉菜单#

.dropdown {
position: relative;
display: inline-block;
}
.dropdown-trigger {
padding: 0.5rem 1rem;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
margin-top: 4px;
min-width: 160px;
background: white;
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all 0.2s ease;
z-index: var(--z-dropdown, 100);
}
.dropdown:hover .dropdown-menu,
.dropdown:focus-within .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown-item {
display: block;
padding: 0.75rem 1rem;
color: #374151;
text-decoration: none;
}
.dropdown-item:hover {
background: #f3f4f6;
}

工具提示#

.tooltip {
position: relative;
display: inline-block;
}
.tooltip::after {
content: attr(data-tip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 0.5rem 0.75rem;
margin-bottom: 8px;
background: #1f2937;
color: white;
font-size: 0.875rem;
white-space: nowrap;
border-radius: 6px;
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s,
visibility 0.2s;
z-index: var(--z-tooltip, 700);
}
/* 小三角 */
.tooltip::before {
content: '';
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #1f2937;
opacity: 0;
visibility: hidden;
transition:
opacity 0.2s,
visibility 0.2s;
}
.tooltip:hover::after,
.tooltip:hover::before {
opacity: 1;
visibility: visible;
}
<button class="tooltip" data-tip="点击保存文档">保存</button>

定位是 CSS 中强大但容易出错的特性。记住:relative 为子元素提供参照,absolute 脱离文档流精确定位,fixed 相对视口固定,sticky 结合两者优点。理解层叠上下文可以帮助你避免 z-index 的常见陷阱。下一篇我们将学习浮动与 BFC,理解另一种影响布局的重要机制。