CSS 定位(position)
定位用来精确控制元素的位置——做弹窗、吸顶导航、tooltip、徽标都靠它。理解五种 position 取值的区别,能解决大部分"叠层"问题。但记住一条原则:能用文档流解决的,就别用定位——定位容易让代码变难维护。
1. 五种取值一览
position 属性有五个取值,核心区别在于"参照谁定位"和"是否脱离文档流"。
/* static:默认值,按文档流排,top/left 无效 */
.normal { position: static; }
/* relative:相对原本位置偏移,不脱离文档流 */
.pushed {
position: relative;
top: 10px; /* 从原位置向下移 10px */
left: 20px; /* 向右移 20px */
}
/* absolute:脱离文档流,相对最近的"非 static 祖先"定位 */
.tooltip {
position: absolute;
top: 100%; /* 父元素底部 */
left: 0;
}
/* fixed:相对浏览器窗口,滚动不跟随 */
.modal {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,.5);
}
/* sticky:滚到指定位置时"吸住" */
.nav {
position: sticky;
top: 0; /* 滚到距顶 0 时吸住 */
}简单对比:
- static:默认,按文档流,top/left 写了也无效。
- relative:不脱离文档流,相对自己原本的位置偏移。常作为 absolute 的"参照系"父级。
- absolute:脱离文档流,相对最近的非 static 祖先定位。没有非 static 祖先就相对
body。 - fixed:相对浏览器窗口,滚动不跟随。适合广告条、悬浮按钮、全屏弹窗遮罩。
- sticky:混合体——正常滚动,但滚到指定位置时"吸住"。适合表头、侧边栏导航。
2. relative + absolute 黄金组合
这是定位最常用的模式——父元素设 relative,子元素设 absolute。这样子元素就以父元素为参照定位,不会"乱跑"。
.container {
position: relative; /* 关键:作为子元素 absolute 的参照系 */
}
.badge {
position: absolute;
top: -8px; /* 在父元素左上角上方一点 */
right: -8px;
background: #ff5722;
color: #fff;
border-radius: 50%;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
font-size: 12px;
}典型场景:卡片右上角的小红点徽标(消息数)、图片上的标签、按钮上的 tooltip。父 relative 子 absolute 是前端开发的高频套路,务必背下来。
注意:父元素如果不设 relative,子元素的 absolute 会"逃出"父级,相对更外层的非 static 祖先定位——这是新手最常踩的坑。看到 absolute 元素位置不对,先检查父级有没有 relative。
3. fixed + 全屏弹窗
fixed 相对浏览器窗口定位,适合做全屏遮罩 + 居中弹窗的经典组合。
/* 全屏遮罩 + 居中弹窗,经典组合 */
.overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0; /* 铺满视口 */
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal {
background: #fff;
padding: 24px;
border-radius: 12px;
max-width: 90%;
width: 400px;
}关键点:
top/left/right/bottom: 0四个方向都设 0,等于铺满整个视口。- 配合 Flex 的
justify-content: center+align-items: center,让弹窗本身在遮罩里居中——比算top: 50%; transform: translate(-50%, -50%)简单得多。 z-index必须设高,确保盖在所有内容之上。
4. sticky 吸顶导航
sticky 是相对较新的取值,解决了"滚动到某位置就吸住"的需求——以前要靠 JS 监听滚动事件才能实现。现在一行 CSS 搞定。
/* 吸顶导航:滚动到顶部时贴住 */
.header {
position: sticky;
top: 0;
background: #fff;
z-index: 100;
box-shadow: 0 2px 8px rgba(0,0,0,.05);
}
/* 注意:sticky 的父元素高度必须比 sticky 元素高,否则没空间"粘" */
/* 另外:父元素不能有 overflow: hidden,否则 sticky 失效 */但 sticky 有几个坑要注意:
- 父元素高度必须比 sticky 元素高,否则没空间让 sticky"粘"——它只在父元素的范围内吸顶。
- 父元素或任何祖先不能有
overflow: hidden/auto/scroll,否则 sticky 失效。这是最常见的"为什么我的 sticky 不工作"。 - 某些老浏览器需要
-webkit-sticky前缀,现代浏览器已直接支持。
5. z-index 层级控制
定位元素会"叠"在一起,z-index 控制谁在上谁在下。值越大越靠上。
.overlay { z-index: 1000; } /* 弹窗最上层 */
.header { z-index: 100; } /* 吸顶导航次之 */
.dropdown { z-index: 50; } /* 下拉菜单 */
.card { z-index: 1; } /* 普通卡片 */
/* 注意:
1. z-index 只对 position 非 static 的元素生效
2. 同层级比 z-index 大的覆盖小的
3. 不同层级的"堆叠上下文"互相独立,z-index 不直接比较
4. 滥用 z-index 容易陷入"军备竞赛",能用文档流就别用定位 */关于 z-index 有几个关键认知:
- 只对非 static 元素生效:没设 position 的元素,z-index 写了也无效。
- 堆叠上下文:某些属性(如
opacity< 1、transform、filter)会创建新的"堆叠上下文",让子元素的 z-index 在这个上下文里独立比较——父级 z-index 低的,子级 z-index 设再高也盖不过父级兄弟。 - 分层规范:推荐项目里定一套 z-index 层级(如 1/10/50/100/1000),全站复用,避免乱堆。
- 能用文档流就别用定位:z-index 军备竞赛是 CSS 维护噩梦的根源。
6. top/right/bottom/left 与 inset 简写
四个方向偏移量,和 margin 简写规则类似(上、右、下、左)。新的 inset 属性可以一次性设四个方向。
7. 何时该用定位
- 该用:弹窗、tooltip、徽标、吸顶导航、悬浮按钮——这些需要脱离文档流的场景。
- 别用:普通内容布局、卡片排列、栏宽分配——这些用 Flex/Grid 更合适。
- 原则:每用一次定位,问问自己"用 Flex 或 Grid 行不行"。如果能,就别用定位。
小结
定位是处理"叠层"和"脱离文档流"需求的工具。掌握五种取值:static 默认、relative 不脱流、absolute 脱流(父 relative 子 absolute)、fixed 视窗固定、sticky 滚动吸顶;z-index 控制层级但要慎用。下一篇讲过渡与动画——让页面真正"动"起来。
← 上一篇 CSS Grid 网格布局
下一篇 CSS 过渡与动画 →