Web 前端学习笔记(三):CSS 布局(浮动 · 定位 · Flex)
浮动、定位、Flex 解决的是同一类问题——把元素摆到想要的位置,只是属于不同年代的方案。放在一起对比,比分开学更容易记住各自适合什么场景。
一、浮动 float
float 最初的用途是实现”文字环绕图片”的效果(就像杂志排版),后来被大量拿来搭多列布局。它的取值很简单:
1 | .left-son { |
浮动的元素会尽量靠向指定方向,多个同向浮动元素会依次紧贴排列,一行放不下就换行。
半脱离文档流
浮动元素会”浮”起来:它原来占据的位置会让给后面的元素,但行内内容(文字)会绕着它排列。这就是”半脱离”——和 position: absolute 的完全脱离不一样。
父元素高度坍塌
这是浮动最经典的坑:
1 | .father { |
如果把 height: 150px 去掉,父元素的高度会变成 0 ——因为浮动的子元素不再参与父元素的高度计算。父元素的背景色、边框都会缩成一条线,后面本来该在下面的内容会顶上来,整个页面就乱了。
demo 里写死 height: 150px 只是临时绕过,页面内容一变高度就不对了。正规做法是清除浮动,让父元素重新”包住”浮动子元素:
| 方案 | 写法 | 说明 |
|---|---|---|
overflow: hidden |
给父元素加 | 最省事,但会裁掉超出父元素的内容,也可能影响 position: sticky |
::after 伪元素 |
见上面注释 | 推荐,不影响其他布局,兼容性也好 |
::after 方案的原理是:在父元素末尾”凭空”生成一个空内容,给它 clear: both,意思是”这个元素的左边和右边都不允许有浮动元素”。于是它被迫排到所有浮动元素下面,父元素的高度自然就被撑开了。
浮动的初心是文字环绕,不是布局。今天要排多列布局,请直接用 Flex 或 Grid——它们没有高度坍塌这类问题。浮动现在的主要用途就剩”文字环绕图片”了。
二、定位 position
定位的关键在于搞清楚**”我相对于谁来偏移”,以及“我原来的位置还占不占”**。
relative:相对定位
1 | .box-relative { |
- 参照物:元素自己原来的位置;
- 原来的空间仍然占着(不脱离文档流),所以后面的元素不会补位,看起来就像元素”飘”出去了一点,留下一个洞。
因为这一点,relative 很少单独用来移动元素,更常见的用法是给父元素加 position: relative,作为子元素绝对定位的参照物。
absolute:绝对定位
1 | .box-absolute { |
- 参照物:最近的已定位祖先元素(即祖先里第一个
position不是static的)。如果所有祖先都没定位,就相对初始包含块(可以粗略理解为页面左上角); - 完全脱离文档流:原来的位置会被后面的元素直接瓜分——demo 里红块后面的方块会往上顶。
这就是为什么”父相子绝”是最常见的搭配:
1 | .father { position: relative; } /* 父:定位参照物,自身不移动 */ |
fixed:固定定位
1 | .box-fixed { |
- 参照物:浏览器视口,和滚动位置无关;
- 完全脱离文档流。
页面滚动时它纹丝不动,所以适合做回到顶部按钮、悬浮客服、固定导航栏。
三者对比
| position | 参照物 | 是否占原位置 | 典型用途 |
|---|---|---|---|
relative |
自己原来的位置 | 占 | 做绝对定位的参照物、微调位置 |
absolute |
最近的已定位祖先 | 不占 | 角标、下拉菜单、弹层 |
fixed |
浏览器视口 | 不占 | 固定导航、回到顶部 |
配套的偏移属性
top / right / bottom / left 用来指定偏移方向和距离。规则是:写 left 就从左边量,写 right 就从右边量,同时写 left 和 right 会拉伸宽度(如果没写 width)。
补充:还有一种 position: sticky,它是 relative 和 fixed 的结合体——在容器内滚动到指定位置前表现得像 relative,超过阈值后就”粘”在那里。本站的导航栏和侧边栏就用了类似的粘性效果。
三、Flex 弹性布局
Flex 是目前最主流的布局方案。用法只有两步:给容器加 display: flex,它的直接子元素自动变成”弹性项目”,然后靠容器上的几个属性统一控制排列方式。
1 | html { |
先理解主轴和交叉轴
Flex 里所有对齐属性都围绕两条轴,这是理解 Flex 的唯一门槛:
1 | 默认 flex-direction: row 时 |
justify-content控制主轴上的对齐;align-items控制交叉轴上的对齐。
一旦把 flex-direction 改成 column,主轴变成垂直方向,这两个属性的作用方向也就跟着互换了——所以不要死记”justify 是水平、align 是垂直”。
容器属性速查
flex-direction —— 决定主轴方向:
| 值 | 排列效果 |
|---|---|
row |
从左到右(默认) |
row-reverse |
从右到左 |
column |
从上到下 |
column-reverse |
从下到上 |
flex-wrap —— 一行放不下时怎么办:
| 值 | 效果 |
|---|---|
nowrap |
不换行,压缩子元素(默认) |
wrap |
换行 |
wrap-reverse |
换行,且行序反向 |
justify-content —— 主轴对齐:
| 值 | 效果 |
|---|---|
flex-start |
靠主轴起点(默认) |
flex-end |
靠主轴终点 |
center |
居中 |
space-between |
两端对齐,中间平均分配 |
space-around |
每个元素两侧等距(导致两端有半个间隙) |
align-items —— 交叉轴对齐:
| 值 | 效果 |
|---|---|
stretch |
拉伸填满(默认) |
flex-start / flex-end |
靠交叉轴起点 / 终点 |
center |
居中 |
baseline |
按文字基线对齐 |
demo 里 6 个方块被 justify-content: center + align-items: center 稳稳地摆在了正中央——你可以边看页边把这两个值改成 space-between、flex-end 试试效果。
和浮动对比一下
同样是”一排方块水平居中”,两种方案的差距:
1 | /* 浮动方案:需要清除浮动,还得靠 margin 硬凑居中 */ |
垂直居中是最能体现差距的地方。用传统方案让一个未知高度的元素垂直居中,得动 absolute + transform 或者 table-cell 之类的技巧;Flex 只要一个 align-items: center。
选择顺序建议:能用 Flex 就用 Flex,二维网格布局(同时控制行和列)再上 Grid。浮动留给文字环绕,定位留给悬浮元素。
小结
| 方案 | 参照物 | 是否占位 | 适合场景 |
|---|---|---|---|
float |
— | 半脱离 | 文字环绕;不要用来搭布局 |
relative |
自己原位置 | 占 | 当绝对定位的参照物 |
absolute |
最近的已定位祖先 | 不占 | 角标、下拉菜单、弹层 |
fixed |
浏览器视口 | 不占 | 固定导航、回到顶部 |
flex |
— | — | 绝大多数一维布局 |
下一篇进入 JavaScript,从导入方式一路写到 DOM 操作和移动端 rem 适配。
本系列其他文章
