03定位

浮动只能「靠边站」,position 定位却能精确到像素:把元素「钉」在你指定的坐标上。 弹窗、角标、吸顶导航、返回顶部按钮,背后全是定位。本课的核心只有一件事—— 搞清楚每个定位值的「参照物」是谁

约 18 分钟 7 个动手实验 弹窗与吸顶全靠它

一、position 五种取值总览

position 一共五个取值。看懂这张表,定位就懂了一大半—— 注意「是否脱离文档流」和「参照物」两列,它们决定了一切行为差异:

position 五值语义表:脱流与否 × 参照物
取值脱离文档流定位参照物典型用途
static否(默认值)无——写 top/left 也没用普通文档流元素
relative否(占位保留自己在文档流中的原位置微调位置、给 absolute 当参照物
absolute是(不占位)最近的非 static 祖先(没有则相对页面初始包含块)弹窗、角标、气泡、精确居中
fixed是(不占位)浏览器视口(滚动条滚不动它)返回顶部、吸顶广告、悬浮客服
sticky否(滚动前在流内)最近的滚动容器 + top 等阈值表头吸顶、通讯录字母条
记忆口诀:static 是路人,relative 是原地挪,absolute 找最近定位祖先, fixed 钉在屏幕上,sticky 滚到才粘住。除了 static,另外四个都叫「定位元素」,才能用 top/right/bottom/left 和 z-index。

二、static 默认与 relative 相对定位

不写 position 时元素就是 static,老老实实待在文档流里, 此时 top / left 这些偏移属性对它完全无效relative 则是「保留占位的挪动」: 元素还在文档流里,原来的位置照常留空(不会被兄弟元素补位),再相对这个原位置偏移。

中间盒子挪走了,原位置还在:把 left: 30px 改成 -30px,它立刻朝左反方向挪
方向容易记反:top: 16px 是「顶边离原位置 16px」→ 盒子向下动; left: 30px 是「左边离原位置 30px」→ 盒子向右动。想让盒子朝反方向走,用负值。

relative 单独用的场景不多(小图标微调、盖层),它更重要的角色是—— 给 absolute 当参照物,这是下一节的主角。

三、absolute 绝对定位:找「最近的非 static 祖先」

absolute 是定位家族的核心,两条铁律:

  • 不占位:元素彻底脱离文档流,兄弟元素当它不存在,直接补位;
  • 参照物是「最近的非 static 祖先」:从父级往上逐层找,第一个 position 不是 static 的祖先(relative / absolute / fixed / sticky 都算)就是它的坐标原点;一个都没有,就相对整个页面(初始包含块)。

这就是著名的参照物链:同一个 absolute 子元素,祖先里谁设了定位,它就贴着谁。 对比下面两个演示——唯一的差别是「中间层有没有 position: relative」:

同样的红标签,左侧贴外层绿框、右侧贴中间橙框:把右边的 .ps-chain .case-b .mid 里的 position: relative 删掉,红标签立刻跳到绿框左上角
新手最常见的问题「absolute 元素满世界乱跑」,几乎都是忘了给父级设 position: relative, 导致参照物一路找到页面根部。习惯写法:父 relative + 子 absolute,成对出现。

四、absolute 实战:角标与绝对定位居中

两个最高频的 absolute 用法。角标:把小徽章钉在卡片右上角,负偏移让它「跨出」卡片边缘; 居中left: 50%; top: 50% 把左上角送到中心,再用 translate(-50%,-50%) 退回自身一半(第 01 课学过的万能居中,这里正是它的主战场)。

角标用负偏移骑在卡片边框上:把 .ps-badgetop 改成 0,角标立刻贴进卡片内沿
角标要用负偏移跨出边缘,前提是祖先没有 overflow: hidden 裁掉它—— 接下来的第 04 课「溢出处理」专门讲这件事。

五、fixed 固定定位:钉在视口上

fixed 的参照物是浏览器视口(viewport)——就是你现在看到的这块屏幕区域。 页面滚动条怎么滚,它都纹丝不动,因此天然适合「返回顶部按钮」「吸顶广告条」「悬浮客服」这类元素。 它同样脱离文档流、不占位。

在右侧预览里滚动内容:橙色条贴顶、绿色按钮贴右下角,永远不动。把 .ps-fx-btnbottom 改成 40px,按钮立刻上移
坑:如果 fixed 元素的任何祖先设置了 transformfilter 等属性, 参照物会从视口变成那个祖先,「钉在屏幕上」就失效了——弹窗组件里最常见这个 bug。

六、sticky 粘性定位:滚到才粘住

sticky 是五个值里最年轻的,可以理解为 relative 和 fixed 的合体:平时待在文档流里(relative 状态), 滚动到设定的阈值(如 top: 0)时「粘」在滚动容器边缘不再走(fixed 状态)。 注意它必须配合 top/right/bottom/left 之一才生效,且粘附范围不超过父元素。

通讯录式分组:滚动这个框,绿色字母条依次吸顶。把 top: 0 改成 top: 24px,字母条就粘在离顶 24px 处
sticky 与 relative / fixed 的差异
对比项relativestickyfixed
平时位置原位置偏移文档流内原位置相对视口
何时偏移始终滚动到阈值后始终
是否占位占位滚动前占位不占位
参照物自己原位置滚动容器视口(除非祖先 transform)
适用微调表头吸顶 / 字母导航返回顶部 / 悬浮
sticky 两大常见失效原因:① 忘了写 top(或其它阈值);② 父元素高度不够或 overflow 设成了 hidden / scroll。粘性范围受父元素边界限制——滚出父元素,它就会跟着被带走。

七、偏移属性与 z-index 层叠顺序

top / right / bottom / left 四个偏移属性负责「钉在哪」: 它们只在定位元素(非 static)身上生效,规定元素对应边缘与参照物对应边的距离,正值朝内、负值朝外。 当元素同时写了相对的两个(如 left 和 right)且没定宽,就会「被拉伸」占满这段空间。

偏移属性一览:只对定位元素生效
属性作用常用值备注
top / bottom元素顶边 / 底边离参照物的距离px%autobottom 正值 = 贴底往上量
left / right元素左边 / 右边离参照物的距离px%autoright 正值 = 贴右往左量
z-index层叠顺序:谁盖谁整数(可负),auto只对定位元素和 flex/grid 子项生效

z-index 解决「盒子叠盒子时谁在上面」:数值大者在上; 数值相同则HTML 里后写的在上(后来者居上)。下面三张卡片故意叠放,试着改它们的 z-index:

三张卡片按 z-index 排序:把 .ps-z-stage .bz-index 改成 9,橙卡立刻翻到最上层
z-index 的天坑:层叠上下文。父元素若自身创建了层叠上下文(如 z-index 不是 auto 的定位元素、 或设了 transform / opacity < 1),子元素的 z-index 只在父元素「内部」比大小, 拿不到整个页面的排名——「我明明写了 9999 怎么还是被盖住」多半是它。

八、本章小结

  • 五种定位:static 默认流内;relative 原地偏移、占位保留;absolute 不占位、贴最近的非 static 祖先;fixed 不占位、钉在视口;sticky 滚动到阈值才粘住。
  • 参照物链是 absolute 的命门:父 relative + 子 absolute 是标配写法。
  • 角标 = absolute + 负偏移;万能居中 = left/top: 50% + translate(-50%,-50%)。
  • fixed 做返回顶部与吸顶;sticky 做表头与字母导航,必须写 top 阈值。
  • 偏移属性 top/right/bottom/left 只对定位元素生效;z-index 大者在上、同值后来者在上。
  • 记住口诀:static 是路人,relative 原地挪,absolute 找定位祖先,fixed 钉屏幕,sticky 滚到粘。
动手练习:做一个「商品卡片」:卡片用 relative,右上角挂 absolute 负偏移的红色圆形「新品」角标; 再做一个 160px 高的相对定位舞台,里面放一个 absolute + translate 居中的标签; 最后给两个叠放的色块分别设 z-index: 1 和 2,交换数值观察盖压关系的变化。