CSS 定位让你可以将元素从正常的文档流中取出,放置到页面的任意位置。从固定的导航栏到弹出的模态框,定位是实现这些常见 UI 模式的关键技术。
position 属性#
position 属性决定了元素的定位方式,有五个可选值:
static:默认值,正常文档流relative:相对定位absolute:绝对定位fixed:固定定位sticky:粘性定位
static(默认值)#
static 是默认值,元素按照正常的文档流排列:
.box { position: static; /* 默认值,通常不需要显式设置 */}static 定位的元素不受 top、right、bottom、left、z-index 属性的影响。
relative(相对定位)#
相对定位让元素相对于自身原本的位置进行偏移:
.box { position: relative; top: 20px; left: 30px;}🎯 关键特点:
- 元素仍然占据原来的空间(不脱离文档流)
- 偏移是相对于元素原本的位置
- 常用作绝对定位元素的参照容器
<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;}🎯 关键特点:
- 元素脱离文档流,不再占据空间
- 相对于最近的
position不为static的祖先定位 - 如果没有已定位的祖先,则相对于初始包含块(通常是视口)
<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;}固定定位也脱离文档流。常见用途:
- 固定导航栏
- 回到顶部按钮
- 浮动客服按钮
- Cookie 通知栏
/* 回到顶部按钮 */.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);}🔶 注意:如果祖先元素设置了 transform、perspective 或 filter 属性,fixed 定位会相对于该祖先而非视口。
sticky(粘性定位)#
粘性定位是 relative 和 fixed 的混合体。元素在滚动到特定位置之前表现为相对定位,之后表现为固定定位:
.section-header { position: sticky; top: 0; background: white; padding: 1rem; border-bottom: 1px solid #e5e7eb;}🎯 粘性定位的触发条件:
- 必须指定
top、right、bottom或left中的至少一个 - 父元素不能设置
overflow: hidden或overflow: auto - 父元素必须有足够的高度
<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;}定位偏移属性#
top、right、bottom、left 用于设置定位元素的偏移量:
.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 简写#
inset 是 top、right、bottom、left 的简写:
.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 轴上的排列顺序。以下情况会创建新的层叠上下文:
- 根元素
<html> position: absolute/relative且z-index不为 autoposition: fixed/stickyopacity小于 1transform不为 nonefilter不为 noneisolation: isolate
/* 创建新的层叠上下文 */.new-context { position: relative; z-index: 0; /* 或任何非 auto 值 */}
/* 也会创建层叠上下文 */.another-context { opacity: 0.99;}层叠顺序#
在同一个层叠上下文内,元素的层叠顺序(从下到上):
- 层叠上下文的背景和边框
z-index为负值的定位元素- 非定位的块级元素
- 浮动元素
- 非定位的行内元素
z-index: 0或z-index: auto的定位元素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 只在同一层叠上下文内比较。child1 和 child2 在不同的层叠上下文中,它们的层叠顺序由父元素决定。
解决方案:管理好层叠上下文的层级,建立统一的 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,理解另一种影响布局的重要机制。