定位布局:position属性全解

定位布局,说白了就是让元素「想放哪儿就放哪儿」。

我刚入行那会儿,总觉得布局用 flex 和 grid 就够了。直到有一天,产品经理说「这个弹窗要盖在所有内容上面」——嗯,那时候我才意识到,position 才是真正的王牌。

position 的五种取值

CSS 的 position 属性有五个值:static、relative、absolute、fixed、sticky。每个值都对应一种定位行为,咱们一个一个说。

取值 定位基准 是否脱离文档流 常用场景
static 无(默认) 否 正常文档流
relative 自身原始位置 否 微调元素位置
absolute 最近的非 static 父元素 是 弹窗、下拉菜单
fixed 视口(viewport) 是 固定导航栏、回到顶部
sticky 父容器 + 视口 否(特殊) 吸顶效果、表格表头

static:默认的「老实人」

static 是默认值。元素老老实实待在文档流里,top、left、right、bottom 全都不起作用。

说白了,你写不写 position: static 都一样。我一般只在重置样式时用到它。

/* 默认行为,写了等于没写 */
.box {
  position: static;
  top: 20px;  /* 无效 */
  left: 30px; /* 无效 */
}

relative:相对自己「挪一挪」

relative 是相对元素原本的位置进行偏移。它不脱离文档流,原来的位置依然被占据。

我在项目中常用它来做两件事:一是微调图标位置,二是作为 absolute 子元素的定位锚点。

.card {
  position: relative;
  top: 10px;   /* 向下偏移 10px */
  left: -5px;  /* 向左偏移 5px */
}
小技巧:relative 配合 z-index 可以提升层级,而不改变布局。我经常用它来修复元素被遮挡的问题。

absolute:彻底「放飞自我」

absolute 会让元素脱离文档流,其他元素会忽略它的存在。它的定位基准是最近的非 static 祖先元素。

如果所有祖先都是 static,那就以 body 为基准。

.parent {
  position: relative; /* 成为锚点 */
}

.child {
  position: absolute;
  top: 0;
  right: 0;  /* 贴在父元素右上角 */
}
注意:忘记给父元素设置 position: relative 是新手最常见的坑。我曾经排查过一个 bug 排查了半小时,结果就是父元素没设 relative,子元素直接飞到了页面角落。

fixed:钉死在屏幕上

fixed 以视口为基准,滚动页面时它纹丝不动。常用于导航栏、悬浮按钮、回到顶部。

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  z-index: 1000;
}

嗯,这里要注意:fixed 元素会覆盖其他内容,所以主体内容要加 padding-top 来避开它。

sticky:粘性定位「吸顶」

sticky 是 relative 和 fixed 的结合体。它在滚动到某个阈值之前是 relative,超过阈值后变成 fixed。

我个人特别喜欢 sticky,因为它不需要 JavaScript 就能实现吸顶效果。

.section-title {
  position: sticky;
  top: 0;          /* 滚动到顶部时粘住 */
  background: #f0f0f0;
  z-index: 10;
}
核心要点:sticky 的生效需要父容器有可滚动的空间,且父容器不能设置 overflow: hidden。

z-index 层叠上下文

z-index 控制元素的堆叠顺序。值越大,越靠上。

但这里有个坑:z-index 只在定位元素(非 static)上生效。你给一个 static 元素设 z-index: 9999,它还是老老实实待在底层。

.modal {
  position: fixed;
  z-index: 1000;  /* 盖住导航栏 */
}

.overlay {
  position: fixed;
  z-index: 999;   /* 在模态框下面 */
}

为什么会这样?因为每个定位元素会创建自己的层叠上下文。子元素的 z-index 只在父上下文中比较。

避坑指南:我曾经遇到一个 bug,模态框死活盖不住导航栏。查了半天发现导航栏的父元素设了 transform: scale(1),这玩意儿会创建新的层叠上下文。解决办法是把模态框移到 body 下直接定位。

实战:固定导航栏

固定导航栏是 fixed 最经典的应用。我一般这样写:

<header class="header">
  <nav>首页 | 关于 | 服务 | 联系</nav>
</header>
<main class="main">
  <!-- 页面内容 -->
</main>

<style>
.header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  background: #2c3e50;
  color: #fff;
  z-index: 100;
}

.main {
  padding-top: 60px; /* 避开导航栏 */
}
</style>

实战:模态框

模态框需要盖住整个页面,并且居中显示。我习惯用 fixed + 居中技巧:

<div class="overlay"></div>
<div class="modal">
  <h3>提示信息</h3>
  <p>你确定要删除这条记录吗?</p>
  <button>确定</button>
  <button>取消</button>
</div>

<style>
.overlay {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background: rgba(0,0,0,0.5);
  z-index: 999;
}

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: #fff;
  padding: 24px;
  border-radius: 8px;
  z-index: 1000;
  box-shadow: 0 4px 20px rgba(0,0,0,0.2);
}
</style>
注意:模态框的 z-index 一定要比遮罩层大。另外,如果页面有 fixed 导航栏,模态框的 z-index 也要比导航栏大。

知识体系结构图

position 定位布局 static 默认文档流 relative 相对自身偏移 absolute 脱离文档流 fixed 相对视口固定 sticky 粘性吸顶 z-index 层叠上下文 定位锚点(父元素) 脱离文档流的影响 固定导航栏 模态框弹窗

这张图把 position 的五种取值、关键概念和实战应用串在了一起。你想想看,掌握了这些,页面里任何元素的位置你都能控制。

可可精品资料库