Day4 学习文档:Position 定位实战
1. 今天要掌握什么
Day4 的目标是把“元素放哪儿”这件事彻底搞明白:
- 理解
relative、absolute、fixed、sticky的区别 - 知道每种定位在什么场景下最合适
- 能做出 3 个常见交互:吸顶导航、角标、回到顶部按钮
2. 大白话理解 Position
可以把页面想象成一张地图,普通元素按“排队规则”从上到下放置。
position 就是告诉浏览器:这个元素是否要“偏离原队列”。
static:默认值,老老实实排队relative:还在队列里,但允许“微调位置”absolute:脱离队列,贴着某个参考盒子定位fixed:脱离队列,直接贴着屏幕定位sticky:平时排队,滚动到阈值后吸附
2.1 两个必须懂的基础词:viewport 和文档流
一、文档流(Normal Flow)
大白话:就是网页里的元素“排队”的方式,默认情况下,它们按照你在HTML里写的顺序,一个接一个地自动摆放。
- 块级元素(比如
<div>、<p>、<h1>):就像地铁里的车厢,每个独占一整节,竖着排,上一个在顶上,下一个在底下,不会并排。 - 行内元素(比如
<span>、<a>、<strong>):就像排队买票的人,大家并排站在一起,从左到右,一行不够了就自动换到下一行。
一句话:文档流就是“正常排队”,你什么都不改,它就这么排。
二、viewport(视口)
大白话:就是你手机或电脑屏幕上用来显示网页的那个矩形区域。
- 在电脑上,视口就是浏览器窗口的内部(不包括工具栏、地址栏)。
- 在手机上,视口比较特殊:因为手机屏幕窄,早期网页都是为电脑设计的(宽度至少960px),如果手机用真实屏幕宽度(比如375px)去显示,网页会被挤得乱七八糟。所以手机浏览器默认用一个虚拟的宽视口(通常是980px)来加载网页,然后缩放显示。这就导致你看不清字,需要手动放大。
**<meta name="viewport"> 标签的作用**:告诉手机浏览器:“别用那个虚拟宽视口了,就用我的实际屏幕宽度来布局”。常见写法:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
意思是:
width=device-width:把视口宽度设成手机屏幕的实际宽度(比如375px)。initial-scale=1.0:不缩放,1个CSS像素对应1个屏幕物理像素。
一句话:viewport 就是“你看网页的那个框框”,移动端必须设置那个meta标签,否则网页会像缩小的蚂蚁。
三、二者关系
- 文档流 是元素在视口内的排列方式。
- 视口 是容纳文档流的容器大小。
举个例子:你把一排积木(文档流)放在一个盒子里(视口)。盒子宽了,积木可能并排;盒子窄了,积木可能换行。
移动端如果不设置 viewport,盒子(视口)会默认宽980px,导致你的积木(元素)看起来很迷你,用户必须双指缩放才能看清。设置了之后,盒子宽度就是手机屏幕宽度,你按正常尺寸写CSS就行。
希望这样解释你彻底明白了。如果还有模糊的地方,可以继续问。
3. 四种核心定位方式(更直观版)
先记一句总口诀:
relative:站在原地,可微调absolute:脱离队伍,找爹定位fixed:钉在屏幕,不跟页面走sticky:先正常滚,后吸顶
3.1 position: relative(站在原地,可微调)
生活类比:
你在排队时,脚还在原位置,但身体可以往前后左右挪一点。
你会看到的效果:
- 这个元素原本位置还占着,不会让后面的元素补上来
- 可以用
top/right/bottom/left微调显示位置
最常见用途(不是“挪自己”,而是“给孩子当参照物”):
- 给卡片加
position: relative,让内部角标用absolute对齐这张卡片
一句话判断:
需要一个“定位锚点”时,先上 relative。
3.2 position: absolute(脱离队伍,找爹定位)
生活类比:
一个人离开队伍,跑去贴着“最近的定位锚点”站位。
你会看到的效果:
- 元素脱离文档流,原位置会被其他元素“顶上来”
- 它会找最近的、
position不是static的祖先作为参照 - 如果没找到,就相对页面定位(常见“跑飞”)
典型场景:
- 卡片角标、关闭按钮、图片文案浮层
一句话判断:
想让元素“贴着某个盒子角落”时,用 absolute + 父级 relative。
3.3 position: relative 和 absolute 的关系(大白话)
3.3.1 relative(相对定位)
大白话:元素原本在文档流里占着位置(排队占位),你可以通过 top/left/right/bottom 让它相对于自己的原位置挪动一下。挪动后,原来的坑位依然空着(其他元素不会挤过来)。
- 常用场景:给绝对定位的父元素做“参照物”。
3.3.2 absolute(绝对定位)
大白话:元素完全脱离文档流(不再排队,也不再占位),其他元素会忽略它,直接填补它原来的位置。它的位置参考系是最近的那个设置了 position(非 static)的祖先元素。如果找不到这样的祖先,就参考视口(但严格说是初始包含块,可以理解为视口)。
3.3.3 它们最经典的配合:父 relative,子 absolute
这是为了让子元素相对于父元素进行绝对定位。
例子:
<div class="parent" style="position: relative;">
<div class="child" style="position: absolute; top: 0; right: 0;">角标</div>
</div>
- 父元素
relative:不挪动自己,只是建立一个定位参照系。 - 子元素
absolute:相对于父元素左上角定位,top:0; right:0就贴在父元素右上角。
为什么父元素不用 absolute? 因为父元素如果 absolute 也会脱离文档流,破坏布局。用 relative 最安全(它不脱离文档流)。
3.3.4 对比表格
| 特性 | relative | absolute |
|---|---|---|
| 是否脱离文档流 | ❌ 不脱离,原位置保留 | ✅ 脱离,原位置被其他元素占据 |
| 定位参照物 | 自身原本的位置 | 最近的非 static 祖先(如果没有,则视口) |
能否用 top/left 移动 | 能,相对于自身原位置 | 能,相对于参照物 |
| 常见用途 | 作为绝对定位的容器、微调位置 | 浮层、角标、弹出菜单 |
3.3.5 一个帮你记忆的生活类比
**relative**:就像你站在排队的位置上,可以稍微往前探一点身子,但你的脚还在原地(别人不能占你的位)。**absolute**:你从队伍里走出来,站在某个参照物(比如墙壁)旁边。你的原位置立刻被后面的人占了。- 父
relative+ 子absolute:你对墙壁(父元素)说:“我要站在你右上角”。墙壁说:“好,我原地不动,你相对于我站。”
3.3.6 一个特殊但重要的点
如果某个祖先元素设置了 transform、perspective、filter 等属性,它会成为 absolute 的参照物(类似 relative),这有时会导致预期外的定位。
总结一句话:
relative是“相对自己原位置微调,不脱队”。absolute是“脱队去找最近的带定位的祖先,没有就找视口”。- 组合使用时,父
relative给子absolute当参照物。
3.4 position: fixed(钉在屏幕,不跟页面走)
生活类比:
把便签纸贴在你的手机屏幕上,不管页面怎么滑,便签都在同一个位置。
你会看到的效果:
- 元素固定在视口(viewport)上
- 页面滚动时它不动
- 也脱离文档流,可能遮挡内容
典型场景:
- 回到顶部按钮
- 悬浮客服入口
一句话判断:
想“永远在屏幕可见区域”就用 fixed。
3.5 position: sticky(先正常滚,后吸顶)
生活类比:
便利贴一开始贴在文档某一行,滚动到顶部后它被“吸”住,不再继续上去。
你会看到的效果:
- 在阈值前,它和普通元素一样参与文档流
- 达到阈值(如
top: 0)后,像fixed一样吸附 - 常需要配
z-index和背景色,避免被内容盖住
典型场景:
- 吸顶导航
- 左侧目录跟随
一句话判断:
想要“滚动到某点才固定”,选 sticky。
4. 你当前页面里的实战映射
4.1 吸顶导航(sticky)
.topbar {
position: sticky;
top: 0;
z-index: 10;
}
解释:导航滚动到页面顶部后会“钉住”。
4.2 角标(relative + absolute)
.badge-card {
position: relative;
}
.badge {
position: absolute;
top: -10px;
right: -10px;
}
解释:角标相对卡片定位,而不是相对整个页面乱跑。
4.3 回到顶部按钮(fixed)
.back-top {
position: fixed;
right: 16px;
bottom: 16px;
}
解释:无论页面滚动到哪里,按钮都固定在屏幕右下角。
5. 常见坑(重点)
absolute位置跑偏
- 原因:父元素没设
position: relative
sticky不生效
- 常见原因:没写
top;或父容器有overflow限制
fixed挡住内容
- 解决:给主内容留底部空间,或调整按钮位置
- 层级覆盖异常
- 解决:配合
z-index控制层级(前提是元素有定位)
6. 提交前自测清单
- 顶部导航滚动时可吸附
- 角标稳定在卡片右上角
- 回到顶部按钮始终固定在右下角
- 手机宽度下无明显遮挡或溢出
- 你能说清这四种定位的适用场景
7. 今天的学习产出模板(可复制到 README)
## Day4 学习总结(Position)
### 我做了什么
- 实现 sticky 吸顶导航
- 实现 relative + absolute 角标
- 实现 fixed 回到顶部按钮
### 我学会了什么
- 四种常见定位方式的差异
- absolute 的参照物查找规则
- sticky 的触发条件
### 我遇到的问题
- (填写你今天遇到的问题)
### 我如何解决
- (填写解决过程)
8. CSS 选择器速记(结合 .fixed-demo)
你在 Day4 页面里看到这段:
.fixed-demo {
position: fixed;
top: 12px;
right: 12px;
}
.fixed-demo 里的 . 是什么?
. 表示 class 选择器,意思是:
- 选中所有
class="fixed-demo"的元素 - 给这些元素应用样式
对应 HTML:
<div class="fixed-demo">我是 fixed 对照条</div>
常见选择器符号(新手高频)
.demo:class 选择器(最常用)#demo:id 选择器(页面唯一)div:标签选择器A B:后代选择器(A 内任意层级的 B)A > B:子代选择器(A 的直接子元素 B)
一句话记忆
.找 class#找 id- 空格找后代
>找亲儿子(直接子元素)
9. HTML 多个 class:class="card badge-card"
它是什么意思?
class="card badge-card" 表示这个元素同时拥有两个 class:
cardbadge-card
在 CSS 里,只要选择器匹配,就会同时应用:
.card { ... }
.badge-card { ... }
为什么要这样写?
常见原因是“组合样式”:
card:通用卡片外观(白底、边框、圆角、内边距)badge-card:额外加position: relative,给角标当定位参照物
这样拆分后,别的卡片可以只复用 card,不必复制一堆样式。
如果两个规则冲突了怎么办?
如果 .card 和 .badge-card 都写了同一个属性(比如 padding),最终生效取决于:
- **选择器优先级(specificity)**更高者优先
- 优先级相同,通常 后写的规则覆盖先写的规则(同文件内从上到下)
CSS 里还有一种“链式 class”(可选进阶)
.card.badge-card {
/* 必须同时有 card 和 badge-card 才会命中 */
}
这和 HTML 写多个 class 是配套的,用来表达“只在特定组合下生效”的样式。
更系统的解释请看下一节:## 10. CSS 优先级 + 链式选择器(进阶但很有用)。
10. CSS 优先级 + 链式选择器(进阶但很有用)
10.1 链式选择器是什么?
链式选择器(也叫“复合选择器”的一种常见写法):
.card.badge-card { }
含义:元素必须同时满足:
- 有
class="card" - 也有
class="badge-card"
所以它比单独的 .card 更“挑剔”,命中范围更小。
对比:
<section class="card">A</section>
<section class="card badge-card">B</section>
.card:A 和 B 都会命中.card.badge-card:只有 B 命中
10.2 链式选择器会不会让优先级变高?
会。链式 class 相当于把多个 class 条件叠在一起,通常比单个 class 更具体。
直觉记忆:
.card:1 个 class.card.badge-card:2 个 class(更具体)
所以在冲突时,.card.badge-card 往往更容易赢过 .card。
10.3 CSS 优先级(specificity)到底比什么?
当两条规则都设置了同一个属性(比如 padding),浏览器要决定用哪条,会先看 优先级,再看 书写顺序(同优先级时,后写覆盖先写)。
新手最常用的优先级直觉(从低到高):
- 标签选择器(如
div、section) - class 选择器(如
.card) - id 选择器(如
#intro) - 行内样式(
style="...",一般不推荐大面积使用) **!important**(尽量别当常规武器)
说明:真实计算比这个更细(还会统计选择器里 class/id/标签的数量),但上面的顺序足够你日常排错。
10.4 两个很容易踩坑的点
- 以为“写在后面就一定赢” 不一定。如果对方选择器优先级更高,你写在后面也可能无效。
- 链式选择器写错
.card .badge-card(中间有空格)是后代选择器,不是链式选择器。
.card.badge-card(中间没空格)才是“同时有两个 class”。
10.5 结合你 Day4 页面的一个判断练习
假设同时存在:
.card { padding: 16px; }
.badge-card { padding: 24px; }
.card.badge-card { padding: 20px; }
对一个 class="card badge-card" 的元素:
- 三个规则都匹配
- 最终
padding通常会落在.card.badge-card(更具体)
如果你发现结果不符合预期,打开 DevTools 看 Computed 面板,能看到最终生效规则与被覆盖原因。
11. border-radius: 999px 是什么“magic”?
它不是魔法,而是一个常见技巧:
把圆角半径写得非常大,让浏览器自动夹到可用最大值。
11.1 为什么写 999px 也不会“溢出”?
浏览器会做限制:圆角不可能超过元素几何允许的范围。
所以你写 999px,实际会被“裁到最大可行圆角”。
效果通常是:
- 长条按钮 -> 胶囊形(两端很圆)
- 接近正方形的按钮 -> 接近圆形
11.2 和 border-radius: 50% 有什么区别?
999px:给“很大固定值”,常用于按钮、标签,尺寸变化时也容易保持圆润50%:按元素自身尺寸比例计算,常用于正方形头像变圆
一句话理解:
999px 更像“我要尽可能圆”,50% 更像“按比例圆”。
11.3 在你 Day4 页面里的实际用途
你的“回到顶部”按钮如果用了:
.back-top {
border-radius: 999px;
}
它会变成胶囊风格,更像悬浮操作按钮。
11.4 常见使用场景
- 悬浮按钮(回到顶部、客服入口)
- 小标签(Tag / Badge)
- 导航中的胶囊按钮
11.5 小提醒
border-radius 只影响“圆角外观”,不影响元素布局流。
你仍需要配合 padding、line-height、width/height 去控制按钮最终形态。
附录:完整 index.html 代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Day4 Position 练习</title>
<style>
*, *::before, *::after {
box-sizing: border-box
}
.fixed-demo {
position: fixed;
top: 0;
right: 20px;
z-index: 100;
background: yellow;
padding: 12px 16px;
border-bottom: 1px solid #e5e5e5;
}
.pre-scroll {
height: 280px;
display: flex;
align-items: center;
justify-content: center;
color: #475569;
background: linear-gradient(180deg, #dbeafe 0%, #eff6ff 100%);
border-bottom: 1px solid #bfdbfe;
}
.topbar {
position: sticky;
top: 0;
z-index: 10;
background: #ffffff;
border-bottom: 1px solid #e5e7eb;
}
.topbar-inner {
max-width: 960px;
margin: 0 auto;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.topbar a {
text-decoration: none;
color: #1d4ed8;
margin-left: 10px;
}
.back-top {
position:fixed;
right: 16px;
bottom: 16px;
border: 1px solid #1d4ed8;
border-radius: 999px;
background: #2563eb;
color: #fff;
text-decoration: none;
padding: 10px 14px;
}
.back-top:hover {
background: #1d4ed8;
}
.filler {
min-height: 1200px;
}
.container {
/* 设置了最大宽度,并且居中显示,并且有内边距 */
max-width: 960px;
margin: 0 auto;
padding: 24px 16px 80px;
}
/* 卡片样式 */
.card {
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
}
/* 角标卡片样式 */
.badge-card {
position: relative;
}
/* 角标样式 */
.badge {
/* 绝对定位,相对于父元素 */
position: absolute;
/* 距离父元素上边10px */
top: -10px;
/* 距离父元素右边10px */
right: -10px;
/* 背景颜色 */
background: #ef4444;
/* 文字颜色 */
color: #fff;
/* 字体大小 */
font-size: 12px;
/* 内边距 */
padding: 4px 8px;
/* 圆角 */
border-radius: 999px;
}
</style>
</head>
<body>
<div class="fixed-demo">我是fixed(一直钉在屏幕右上角)</div>
<section class="pre-scroll">
<p>先向下滚动,再观察 topbar 何时开始吸顶</p>
</section>
<header class="topbar">
<div class="topbar-inner">
<strong>Day4 Position 实战</strong>
<nav>
<a href="#intro">介绍</a>
<a href="#absolute-relative">角标</a>
<a href="#sticky-fixed">笔记</a>
</nav>
</div>
</header>
<main class="container">
<section class="card" id="intro">
<h1>Day4 Position 练习页面</h1>
<p>本日目标:掌握 relative / absolute / fixed / sticky 的使用场景。</p>
</section>
<section class="card badge-card" id="absolute-relative">
<span class="badge">NEW</span>
<h2>absolute + relative 角标示例</h2>
<p>父元素用 <code>position: relative</code>,角标用 <code>position: absolute</code>。</p>
</section>
<section class="card" id="sticky-fixed">
<h2>sticky + fixed 说明</h2>
<p>顶部导航使用 <code>position: sticky</code>,滚动到顶部后保持可见。</p>
<p>右下角按钮使用 <code>position: fixed</code>,始终固定在视口位置。</p
</section>
<section class="filler"></section>
<a href="#intro" class="back-top">回到顶部</a>
</main>
</body>
</html>