第六章:CSS 布局:从 Flexbox 到 Grid 的布局之道 摘要 : 欢迎来到 CSS 世界的“终局之战”——布局。可以毫不夸张地说,掌握了布局,就等于掌握了 99% 的 CSS 。本章是一个内容极其丰富的“大章节”,我们将系统性地学习从一维的 Flexbox 到二维的 Grid 这两大现代布局利器,并掌握 Position 定位的精准微操与 Multi-column 的巧妙应用。更重要的是,我们会将所有这些技术融合进“响应式设计”的思维框架中,让您有能力构建适应任何屏幕尺寸的现代化网页。请务必多加练习,本章的知识将是您未来前端生涯中最宝贵的财富。
学习路径说明 : 您会注意到,本章我们将重点讲解 Flexbox 和 Grid,而对 float
(浮动) 等传统技术则一笔带过。这是因为,float
最初是为“图文环绕”而设计的,用它来做全局布局是一种“滥用”,会带来层叠塌陷、需要清除浮动等无穷的副作用,在 2025 年的今天,它已被现代布局方案完全取代。我们的目标是直接学习当前业界的最佳实践,而非背负历史包袱。
在本章的学习地图中,我们将一步步成为布局大师:
首先,我们将掌握 一维布局的王者——Flexbox ,完美解决组件内的对齐问题。 接着,我们将学习 二维布局的终极方案——Grid ,随心所欲地绘制整个页面蓝图。 然后,我们会探索 多列布局 (Multi-column) 的妙用,用最简单的代码实现瀑布流。 之后,我们将学习 Position 定位 ,掌握脱离常规文档流的“魔法”。 最后,我们将所有知识融会贯通,学习 响应式设计的核心 ,让我们的页面在手机、平板和桌面端都能完美呈现。 6.1. Flexbox 弹性布局:一维空间的统治者 Flexbox 是为 一维布局 而生的。无论是水平行内还是垂直列内,只要你需要在一条轴线上对齐、分布、排序一组元素,Flexbox 就是最简单、最强大的工具。
6.1.1. 核心概念:主轴与交叉轴 一旦为一个元素设置了 display: flex;
,它就成为了一个 Flex 容器 (flex container) ,其所有直接子元素都自动成为 Flex 项目 (flex item) 。
容器内部存在两根无形的轴:
主轴 (main axis) : 所有项目默认沿着主轴排列。默认是水平方向。交叉轴 (cross axis) : 与主轴垂直的轴。默认是垂直方向。6.1.2. 容器属性 (Flex Container) 这些属性写在 父元素 上,用于指挥所有子元素的整体排列。我们将逐一深入讲解。
1. flex-direction
:定义主轴方向 此属性决定了项目排列的 方向 ,即主轴是水平还是垂直。
值 描述 row
默认值 。主轴为水平方向,起点在左端。row-reverse
主轴为水平方向,起点在右端。 column
主轴为垂直方向,起点在上沿。 column-reverse
主轴为垂直方向,起点在下沿。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <style > .direction-demo { display : flex; border : 1px solid #ccc ; margin-bottom : 10px ; } .direction-demo div { width : 60px ; height : 60px ; background : #add8e6 ; text-align : center; line-height : 60px ; margin : 5px ; } </style > <strong > flex-direction: row (默认)</strong > <div class ="direction-demo" style ="flex-direction: row;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-direction: row-reverse</strong > <div class ="direction-demo" style ="flex-direction: row-reverse;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-direction: column</strong > <div class ="direction-demo" style ="flex-direction: column;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-direction: column-reverse</strong > <div class ="direction-demo" style ="flex-direction: column-reverse;" > <div > 1</div > <div > 2</div > <div > 3</div > </div >
2. flex-wrap
:定义是否换行 此属性决定了当一条轴线排不下所有项目时,项目是否换行。
值 描述 nowrap
默认值 。不换行,所有项目会被压缩以适应单行。wrap
换行,第一个项目在新行的上方。 wrap-reverse
换行,第一个项目在新行的下方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <style > .wrap-demo { display : flex; width : 220px ; border : 1px solid #ccc ; margin-bottom : 10px ; } .wrap-demo div { width : 80px ; height : 80px ; background : #b0e0e6 ; margin : 5px ; text-align : center; line-height : 80px ; } </style > <strong > flex-wrap: nowrap (默认, 项目被压缩)</strong > <div class ="wrap-demo" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-wrap: wrap</strong > <div class ="wrap-demo" style ="flex-wrap: wrap;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-wrap: wrap-reverse</strong > <div class ="wrap-demo" style ="flex-wrap: wrap-reverse;" > <div > 1</div > <div > 2</div > <div > 3</div > </div >
3. justify-content
:定义主轴对齐方式 这是最常用的容器属性之一,它定义了项目在 主轴 上的对齐和分布方式。
值 描述 flex-start
默认值 。项目向主轴起点对齐。flex-end
项目向主轴终点对齐。 center
项目在主轴上居中。 space-between
两端对齐,项目之间的间隔都相等。 space-around
每个项目两侧的间隔相等。项目之间的间隔比项目与边框的间隔大一倍。 space-evenly
所有间隔完全相等,包括项目与边框之间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <style > .jc-demo { display : flex; height : 80px ; border : 1px solid #ccc ; margin-bottom : 10px ; } .jc-demo div { width : 60px ; background : #87ceeb ; text-align : center; line-height : 80px ; } </style > <strong > flex-start (默认):主轴向前对齐</strong > <div class ="jc-demo" style ="justify-content: flex-start;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > flex-end:主轴向后对齐</strong > <div class ="jc-demo" style ="justify-content: flex-end;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > center:主轴居中</strong > <div class ="jc-demo" style ="justify-content: center;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > space-between:主轴两端对齐</strong > <div class ="jc-demo" style ="justify-content: space-between;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > space-around:主轴两端对齐,项目间距相等</strong > <div class ="jc-demo" style ="justify-content: space-around;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > <strong > space-evenly:主轴两端对齐,项目间距相等</strong > <div class ="jc-demo" style ="justify-content: space-evenly;" > <div > 1</div > <div > 2</div > <div > 3</div > </div >
4. align-items
:定义交叉轴对齐方式 (单行) 它定义了项目在 交叉轴 (默认是垂直方向)上的对齐方式。
值 描述 stretch
默认值 。如果项目未设置高度或设为 auto,将占满整个容器的高度。flex-start
交叉轴的起点对齐。 flex-end
交叉轴的终点对齐。 center
交叉轴的中点对齐。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .ai-demo { display : flex; height : 500px ; border : 1px solid #ccc ; margin-bottom : 10px ; } .ai-demo div { width : 60px ; background : #b0e0e6 ; text-align : center; line-height : 150px ; } </style > </head > <body > <div class ="ai-demo" style ="align-items: flex-end;" > <div > 1</div > <div > 2</div > <div > 3</div > </div > </body > </html >
5. align-content
:定义多行内容的对齐方式 注意 : 此属性仅在项目 换行 后(即 flex-wrap: wrap;
且有多行内容时)才生效。它控制的是 多根轴线 作为一个整体,在交叉轴上的对齐方式。
值 描述 stretch
默认值 。轴线占满整个交叉轴。flex-start
与交叉轴的起点对齐。 flex-end
与交叉轴的终点对齐。 center
与交叉轴的中点对齐。 space-between
与交叉轴两端对齐,轴线之间的间隔平均分布。 space-around
每根轴线两侧的间隔都相等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <style > .ac-demo { display : flex; flex-wrap : wrap; height : 300px ; width : 250px ; border : 1px solid #ccc ; margin-bottom : 10px ; } .ac-demo div { width : 60px ; height : 60px ; background : #f0f8ff ; margin : 5px ; text-align :center; line-height :60px ; } </style > <strong > align-content: center (可修改查看其它效果)</strong > <div class ="ac-demo" style ="align-content: flex-end;" > <div > 1</div > <div > 2</div > <div > 3</div > <div > 4</div > <div > 5</div > <div > 6</div > <div > 7</div > <div > 8</div > <div > 9</div > </div >
6. flex-flow
:方向与换行的简写 flex-flow
是 flex-direction
和 flex-wrap
两个属性的简写形式,用的很少,知道就可以了
1 2 3 4 .container { flex-flow : row wrap; }
6.1.3. 项目属性 (Flex Item) 这些属性写在 子元素(项目) 上,用于定义单个项目的特殊行为。
属性 核心描述 order
改变项目排列顺序 (数值越小越靠前) flex-grow
定义项目的放大比例 (分配剩余空间) flex-shrink
定义项目的缩小比例 (处理空间不足) flex-basis
定义项目的基础尺寸 flex
(核心) 上面三者的简写,如 flex: 1 1 0
,代表着align-self
允许单个项目覆盖容器的 align-items
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <style > .flex-container-item { display : flex; align-items : flex-start; height : 150px ; border : 1px solid #ccc ; } .item-prop { padding : 10px ; border : 1px solid #999 ; } .item-p1 { background-color : #fbe9e7 ; order : 2 ; } .item-p2 { background-color : #e3f2fd ; flex-grow : 1 ; } .item-p3 { background-color : #e8f5e9 ; align-self : center; } .item-p4 { background-color : #f9fbe7 ; order : -1 ; } </style > <div class ="flex-container-item" > <div class ="item-prop item-p1" > Item 1 (order: 2)</div > <div class ="item-prop item-p2" > Item 2 (flex-grow: 1)</div > <div class ="item-prop item-p3" > Item 3 (align-self: center)</div > <div class ="item-prop item-p4" > Item 4 (order: -1)</div > </div >
6.1.4. 实战:通过游戏学习布局 任务 : 通关 24 关 flexboxfroggy,通过我们学习的知识
点击查看最后一关的答案 1 2 3 4 flex-wrap :wrap-reverse;align-content :space-between;flex-direction :column-reverse;justify-content :center;
6.2. Grid 网格布局:二维平面的上帝视角 如果说 Flexbox 是一维的专家,那么 Grid 就是二维布局 的上帝。它将容器划分为行和列,允许我们将项目精确地放置在任意单元格中,是构建整个页面宏观布局的终极方案。
6.2.1. 核心概念
Grid 容器 (grid container) : 应用 display: grid
的元素。Grid 项目 (grid item) : 容器的直接子元素``。Grid 线 (grid line) : 划分网格的水平和垂直线。Grid 轨道 (grid track) : 两条相邻网格线之间的空间(即一行或一列)。Grid 单元格 (grid cell) : 四条网格线包围的最小单位。Grid 区域 (grid area) : 一个或多个单元格组成的矩形区域。6.2.2. 容器属性 这些属性写在父元素 上,用于定义整个网格的结构和对齐方式。
1.定义网格轨道 grid-template-columns grid-template-rows 这两个核心属性分别用于定义网格的列和行。
值 描述 <length>
使用 px
, em
等固定单位。 <percentage>
使用相对于容器尺寸的百分比。 fr
(核心) "分数"单位,用于按比例分配可用空间。repeat()
用于创建重复的轨道模式,如 repeat(3, 1fr)
表示创建3个等宽的列。 minmax()
定义一个尺寸范围,如 minmax(100px, 1fr)
表示最小100px,最大占一份。 auto
由浏览器根据内容决定尺寸。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .grid-template-demo { display : grid; border : 1px solid #ccc ; grid-template-columns : 100px auto 1 fr; grid-template-rows : repeat (2 , 1 fr); gap : 10px ; } .grid-template-demo div { background : #f0f8ff ; border : 1px solid #333 ; text-align : center; padding : 20px 0 ; } </style > </head > <body > <div class ="grid-template-demo" > <div > Row 1, Col 1<br > 100px</div > <div > Row 1, Col 2<br > auto</div > <div > Row 1, Col 3<br > 1fr</div > <div > Row 2, Col 1<br > 100px</div > <div > Row 2, Col 2<br > auto</div > <div > Row 2, Col 3<br > 1fr</div > </div > </body > </html >
2.定义网格区域 这是一个极具表现力的属性,允许你通过“画出”区域名称来定义布局。
值 描述 字符串 每个字符串代表一行,字符串内的名称定义了该行的列区域。 .
一个点号 (.
) 代表一个空的单元格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .areas-demo { display : grid; height : 300px ; grid-template-columns : repeat (4 , 1 fr); grid-template-rows : 100px auto 100px ; gap : 10px ; grid-template-areas : "header header header header" "sidebar main main ." "footer footer footer footer" ; } .areas-demo div { display : grid; place-items : center; } .area-header { grid-area : header; background-color : #add8e6 ; } .area-sidebar { grid-area : sidebar; background-color : #b0e0e6 ; } .area-main { grid-area : main; background-color : #e0ffff ; } .area-footer { grid-area : footer; background-color : #add8e6 ; } </style > </head > <body > <div class ="areas-demo" > <div class ="area-header" > Header</div > <div class ="area-sidebar" > Sidebar</div > <div class ="area-main" > Main</div > <div class ="area-footer" > Footer</div > </div > </body > </html >
grid-area
是一个功能非常强大的属性,它既可以用于将项目放置到命名区域 ,也可以作为基于网格线定位 的终极简写形式。
方式一:分配到命名区域 这是 grid-area
与 grid-template-areas
配合使用的场景,用法非常直观,也如上述示例一样
方式二:作为网格线定位的简写 grid-area
也是 grid-row-start
/ grid-column-start
/ grid-row-end
/ grid-column-end
四个属性的简写。
语法 : grid-area: <row-start> / <col-start> / <row-end> / <col-end>;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .lines-shorthand-demo { display : grid; background : #f0f0f0 ; border : 3px dashed #ccc ; height : 300px ; grid-template-columns : repeat (5 , 1 fr); grid-template-rows : repeat (5 , 1 fr); gap : 5px ; } .lines-shorthand-demo div { display : grid; place-items : center; background-color : #ffcdd2 ; } .highlight-item { grid-area : 2 / 2 / 5 / 5 ; background-color : #c8e6c9 ; color : #1b5e20 ; font-weight : bold; } </style > </head > <body > <div class ="lines-shorthand-demo" > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div class ="highlight-item" > Highlight Area</div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > <div > </div > </div > </body > </html >
3. gap
:定义网格间距 用于设置行与行、列与列之间的间距。
值 描述 gap: <row-gap> <column-gap>;
分别设置行间距和列间距。 gap: <value>;
行间距和列间距都设为同一个值。
4. 单元格内容对齐 这两个属性用于控制项目内容 在其所在的单元格 内部的对齐方式。可以把单元格想象成一个小房间,而项目内容(文字、图片等)就是房间里的家具,*-items
决定了家具如何在这个房间里摆放。
属性 核心描述 justify-items
单元格内容的水平 对齐 align-items
单元格内容的垂直 对齐
start
: 对齐到单元格的起始边(左/上)。end
: 对齐到单元格的结束边(右/下)。center
: 在单元格内居中。stretch
: (默认值) 将项目内容拉伸,填满整个单元格空间。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .items-align-demo { display : grid; height : 400px ; width : 400px ; border : 3px dashed #ccc ; background : #f0f0f0 ; grid-template-columns : 1 fr 1 fr; grid-template-rows : 1 fr 1 fr; gap : 10px ; border : 1px solid #ccc ; } .items-align-demo div { display : grid; background-color : #e0e0e0 ; padding : 10px ; justify-items : center; align-items : center; } </style > </head > <body > <div class ="items-align-demo" > <div > Item 1</div > <div > Item 2</div > <div > Item 3</div > <div > Item 4</div > </div > </body > </html >
5. 网格整体对齐 核心前提 :这两个属性只有在网格的总尺寸小于其容器尺寸 时才会生效。它们控制的是整个网格(所有单元格作为一个整体) ,在容器这个“大画框”里的对齐和分布方式。
属性 核心描述 justify-content
整个网格作为一个整体的水平 对齐与分布 align-content
整个网格作为一个整体的垂直 对齐与分布
start
: 整体网格靠向容器的起始边(左/上)。end
: 整体网格靠向容器的结束边(右/下)。center
: 整体网格在容器内居中。space-between
/ space-around
/ space-evenly
: 控制网格轨道之间的分布方式。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .content-align-demo { display : grid; height : 400px ; width : 400px ; background : #f0f0f0 ; border : 3px dashed #ccc ; grid-template-columns : 100px 100px ; grid-template-rows : 100px 100px ; gap : 10px ; justify-content : start; align-content : start; } .content-align-demo div { background-color : #c8e6c9 ; display : grid; place-items : center; } </style > </head > <body > <div class ="content-align-demo" > <div > 1</div > <div > 2</div > <div > 3</div > <div > 4</div > </div > </body > </html >
6.2.3. 项目属性 (Grid Item) 这些属性写在**子元素(项目)**上,用于定义单个项目在网格中的位置和行为。
1. 基于网格线定位 通过指定项目从哪条网格线开始、到哪条网格线结束,来放置项目。
属性 描述 grid-column-start
/ end
定义项目占据的列范围。 grid-row-start
/ end
定义项目占据的行范围。 grid-column
/ grid-row
上述属性的简写,如 1 / 3
或 1 / span 2
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .lines-demo { display : grid; background : #f0f0f0 ; border : 3px dashed #ccc ; grid-template-columns : repeat (4 , 1 fr); grid-template-rows : repeat (2 , 100px ); gap : 10px ; } .lines-demo div { display : grid; place-items : center; } .item-a { grid-column : 2 / span 2 ; grid-row : 1 / 3 ; background-color : #ffcdd2 ; } .item-b { background-color : #c8e6c9 ; } .item-c { background-color : #bbdefb ; } .item-d { grid-column : 4 ; grid-row : 2 ; background-color : #ffcdd2 ; } </style > </head > <body > <div class ="lines-demo" > <div class ="item-a" > A</div > <div class ="item-b" > B</div > <div class ="item-c" > C</div > <div class ="item-d" > D</div > </div > </body > </html >
2. justify-self
和 align-self
允许单个项目覆盖容器定义的 justify-items
和 align-items
,实现独立对齐。
属性 描述 justify-self
单个项目内容的水平 对齐 align-self
单个项目内容的垂直 对齐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .self-demo { display : grid; height : 400px ; width : 400px ; border : 3px dashed #ccc ; background : #f0f0f0 ; grid-template-columns : repeat (3 , 1 fr); grid-template-rows : 100px ; gap : 10px ; } .self-demo div { background-color : #f3e5f5 ; padding : 10px ; } .special-item { align-self : center; } </style > </head > <body > <div class ="self-demo" > <div > Item 1</div > <div class ="special-item" > Special Item</div > <div > Item 3</div > </div > </body > </html >
6.2.4. 实战:通过游戏学习布局 任务 : 通关 28 关 Grid Garden,通过我们学习的知识,将萝卜种到它们该去的地方。
6.3. Position 定位:脱离常规的精准微操 摘要 : 本节我们将学习一种全新的布局维度——定位 (Positioning) 。您将学习如何使用 position
属性,让元素“脱离”常规的文档流,实现覆盖、固定、粘滞等高级效果。这是实现模态框、下拉菜单、固定导航栏等复杂 UI 组件的必备知识。
6.3.1. 核心前提:理解文档流 在学习定位之前,我们必须先清晰地理解什么是“常规文档流”。在默认状态下,页面元素会遵循一套既定的排列规则:
块级元素 (Block) : 从上到下垂直排列,每个元素独占一行。行内元素 (Inline) : 在水平方向上从左到右依次排列,遇到行尾会自动换行。这套规则就是文档流。而 position
属性,就是赋予我们打破这套常规规则,让元素“飞”出常规队列的能力。
1 2 3 4 5 6 7 8 9 10 11 12 <style > .flow-box { border : 1px solid #ccc ; padding : 10px ; margin : 10px ; } .flow-box div { background-color : #e3f2fd ; border : 1px solid #90caf9 ; padding : 10px ; margin-bottom : 5px ; } .flow-box span { background-color : #fbe9e7 ; border : 1px solid #ffab91 ; padding : 5px ; } </style > <div class ="flow-box" > <div > 块级元素 1</div > <div > 块级元素 2</div > <span > 行内元素 A</span > <span > 行内元素 B</span > <span > 行内元素 C</span > </div >
6.3.2. 定位五模式核心对比 position
属性共有五个值,下表可以帮助我们从宏观上快速把握它们的核心区别。
模式 脱离文档流 定位参照物 核心应用场景 static
否 无 默认状态,无定位 relative
否 (仍占原始空间) 自身原始位置 作为 absolute
的参照物 absolute
是 最近的非 static
祖先 弹窗、角标、覆盖层 fixed
是 浏览器视口 固定导航、返回顶部 sticky
滚动到阈值后 最近的滚动父级 吸顶导航、表格标题
6.3.3. 核心模式详解与实战 相对定位 (relative
) 相对定位非常特殊,它遵循“身在曹营心在汉”的原则:
它在文档流中依然占据着原来的空间 ,不会影响其他元素的布局。 它可以使用 top
, right
, bottom
, left
属性,相对于自己的原始位置 进行偏移。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <style > .relative-demo div { width : 100px ; height : 100px ; display : grid; place-items : center; color : white; } .box-a { background-color : #a5d6a7 ; } .box-b { background-color : #ef9a9a ; position : relative; top : 30px ; left : 30px ; } .box-c { background-color : #90caf9 ; } </style > <div class ="relative-demo" > <div class ="box-a" > Box A</div > <div class ="box-b" > Box B (Relative)</div > <div class ="box-c" > Box C</div > </div >
绝对定位 (absolute
) 与 “父相子绝” 这是定位中最核心、最重要的应用模式。
position: absolute;
会让元素完全脱离文档流 。它会向上寻找所有祖先元素,以第一个 position
值不为 static
的祖先元素 作为自己的定位参照物。 如果找不到这样的祖先,它最终会相对于 <body>
定位。 为了将一个绝对定位元素限制在其直接父元素内部,我们诞生了黄金组合——“父相子绝”:
父级 : position: relative;
(让父级成为定位参照物,但自身不脱离文档流)子级 : position: absolute;
(让子级脱离文档流,并相对于父级定位)实战: 在卡片右上角添加“Hot”徽章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <style > .card { width : 250px ; border : 1px solid #ccc ; border-radius : 8px ; font-family : sans-serif; margin : 50px auto; position : relative; } .card img { width : 100% ; display : block; border-radius : 8px 8px 0 0 ; } .card-body { padding : 15px ; box-shadow : 0 0 10px rgba (0 , 0 , 0 , 0.1 ); } .badge { position : absolute; top : -10px ; right : -10px ; background-color : #e74c3c ; color : white; padding : 5px 10px ; border-radius : 5px ; font-size : 14px ; } </style > <div class ="card" > <img src ="https://picsum.photos/seed/phone/400/250" alt ="Product Image" > <div class ="card-body" > <h4 > 产品标题</h4 > <p > 这是一段产品描述文字。</p > </div > <div class ="badge" > Hot</div > </div >
固定定位 (fixed
) position: fixed;
会让元素脱离文档流,并相对于浏览器视口 进行定位。这意味着即使用户滚动页面,该元素的位置也永远不会改变。
实战: “返回顶部”按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > html { scroll-behavior : smooth; } h1 { height : 1000px ; background-color : #2980b9 ; color : white; display : grid; place-items : center; } .placeholder { height : 2000px ; } .backTop { position : fixed; bottom : 30px ; right : 30px ; width : 50px ; height : 50px ; background-color : #2980b9 ; color : white; display : grid; place-items : center; border-radius : 50% ; text-decoration : none; } </style > </head > <body > <h1 > 顶部区域</h1 > <div class ="placeholder" > </div > <a href ="#" class ="backTop" > △</a > </body > </html >
6.3.4. 综合实战:创建一个居中模态框 (Modal) 任务 : 综合运用 position: fixed
和 z-index
,创建一个覆盖全屏的半透明遮罩层,并在其上居中显示一个模态框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .modal-overlay { position : fixed; top : 0 ; left : 0 ; width : 100% ; height : 100% ; background-color : rgba (0 , 0 , 0 , 0.6 ); z-index : 1000 ; display : flex; justify-content : center; align-items : center; } .modal-content { background-color : white; padding : 30px ; border-radius : 8px ; width : 80% ; max-width : 500px ; text-align : center; } .modal-overlay { display : none; } </style > </head > <body > <button class ="open-modal" > 打开模态框</button > <div class ="modal-overlay" > <div class ="modal-content" > <h3 > 这是一个模态框</h3 > <p > 这里是模态框的内容。遮罩层使用了 position: fixed,模态框本身通过 Flexbox 在遮罩层内居中。</p > <button > 关闭</button > </div > </div > <script > const openModal = document .querySelector ('.open-modal' ); const modalOverlay = document .querySelector ('.modal-overlay' ); openModal.addEventListener ('click' , () => { modalOverlay.style .display = 'flex' ; }); </script > </body > </html >
6.4. 多列布局 (Multi-column):优雅实现内容分栏与瀑布流 摘要 : 本节我们将学习一个巧妙而高效的布局工具——多列布局 。您将学习如何像排版报纸和杂志一样,轻松地将大段文本内容分割成多列以提升可读性。更重要的是,我们将通过一个实战案例,向您展示如何仅用三行核心 CSS 代码就实现一个完美的、响应式的图片瀑布流布局,这是一个在现代网页设计中非常流行且实用的技巧。
6.4.1. 核心属性详解 多列布局的所有属性都应用于容器元素,它会将容器内的所有子元素(无论块级还是行内)自动分配到各列中。
属性 核心描述 column-count
固定列的数量。 column-width
定义每列的理想宽度,浏览器会据此自动调整列数,实现响应式。 columns
count
和 width
的简写属性。column-gap
定义列与列之间的间距。 column-rule
定义列与列之间的分隔线样式,语法与 border
类似。 column-span:all
让标题横跨所有列 break-inside:avoid
避免在元素内部断开换行,让元素尽量完整显示在同一列。
深入讲解 column-count
与 column-width
这两个属性是多列布局的核心,通常我们只使用其中一个来驱动布局:
column-count
(固定列数) : 当你希望布局始终保持 特定数量的列(例如,一个三栏文章),无论容器宽度如何变化时,使用此属性。column-width
(自适应列数) : 当你希望布局响应式 地变化时,使用此属性。你只需定义一个“理想”的列宽(例如 200px
),浏览器会自动计算在当前容器宽度下,能容纳多少个这样的列。当容器变宽,列数会自动增加;容器变窄,列数会自动减少。这是实现响应式瀑布流的关键。 6.4.2. 实战应用 实战一:报纸式文章排版 任务 : 将一段长文本自动格式化为三列,并在列与列之间添加一条浅灰色分隔线,同时让文章标题横跨所有列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <style > .newspaper-article { width : 90% ; margin : auto; border : 1px solid #ddd ; padding : 20px ; column-count : 3 ; column-gap : 40px ; column-rule : 1px solid #eee ; } .newspaper-article h2 { column-span : all; text-align : center; margin-top : 0 ; margin-bottom : 20px ; } .newspaper-article p { text-align : justify; line-height : 1.7 ; } </style > <article class ="newspaper-article" > <h2 > CSS 多列布局的艺术</h2 > <p > 多列布局是一个经常被低估的现代布局工具,它可以轻松地将一段连续的内容(如文本)分割成报纸或杂志那样的多列。这种布局方式不仅美观,还能显著提高长篇文本的可读性,因为它避免了用户视线需要进行过长的水平移动。</p > <p > 要使用多列布局,你只需在容器元素上应用几个简单的 CSS 属性。最核心的属性是 column-count 和 column-width。前者用于定义固定的列数,而后者则定义一个理想的列宽,浏览器会根据容器的可用空间自动计算出合适的列数,从而轻松实现响应式效果。这使得多列布局也成为创建图片瀑布流的一种极其简单高效的方法。</p > <p > 除了基本的列数和宽度,我们还可以通过 column-gap 来控制列与列之间的间距,使用 column-rule 来在列间添加装饰性的分隔线。更有趣的是,通过 column-span 属性,我们可以让某个子元素(比如一个大标题或者一张关键图片)横跨所有列,打破单调的布局,创造出更富吸引力的视觉焦点。</p > </article >
实战二:纯 CSS 图片瀑布流 任务 : 创建一个响应式的图片瀑布流布局。图片会根据浏览器窗口宽度自动重新排列成不同的列数,并且每张图片都保持完整,不会被列分割。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > .waterfall-container { column-width : 220px ; column-gap : 15px ; width : 90% ; margin : auto; } .waterfall-item { width : 100% ; height : auto; margin-bottom : 15px ; border-radius : 8px ; break-inside : avoid; display : block; } </style > <script src ="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer > </script > </head > <body > <div class ="waterfall-container" x-data ="{ images: [ { seed: 'fall1', height: 600 }, { seed: 'fall2', height: 500 }, { seed: 'fall3', height: 650 }, { seed: 'fall4', height: 450 }, { seed: 'fall5', height: 700 }, { seed: 'fall6', height: 520 }, { seed: 'fall7', height: 580 }, { seed: 'fall8', height: 480 }, { seed: 'fall9', height: 620 }, { seed: 'fall10', height: 540 }, { seed: 'fall11', height: 680 }, { seed: 'fall12', height: 420 }, { seed: 'fall13', height: 750 }, { seed: 'fall14', height: 460 }, { seed: 'fall15', height: 590 }, { seed: 'fall16', height: 510 }, { seed: 'fall17', height: 640 }, { seed: 'fall18', height: 470 }, { seed: 'fall19', height: 720 }, { seed: 'fall20', height: 550 }, { seed: 'fall21', height: 610 }, { seed: 'fall22', height: 490 }, { seed: 'fall23', height: 660 }, { seed: 'fall24', height: 430 } ] }" > <template x-for ="image in images" :key ="image.seed" > <img class ="waterfall-item" :src ="`https://picsum.photos/seed/${image.seed}/400/${image.height}`" > </template > </div > </body > </html >
请尝试在此将代码复制到Vs Code中,启用 F12 浏览器 拉动浏览器窗口查看效果
6.5. 响应式设计:让布局适应万千屏幕 摘要 : 本节我们将学习现代网页开发的基石——响应式设计 。这并非一种新的布局技术,而是一种设计思想与方法论 。我们将学习其三大核心支柱:流式网格、弹性图片和媒体查询 。通过掌握这些,您将能够让一套代码在手机、平板和桌面电脑上呈现出截然不同却都同样完美的布局效果,为所有用户提供最佳的浏览体验。
6.5.1. 核心概念与基石 响应式设计的实现依赖于几项关键的 CSS 技术和开发思想。
视口 (Viewport) 元标签 这是开启移动端适配的必备第一步 ,是响应式设计的“准生证”。这行代码必须被添加到 HTML 文件的 <head>
标签中。
1 <meta name ="viewport" content ="width=device-width, initial-scale=1.0" >
它告诉移动端浏览器:
width=device-width
: 将视口的宽度设置为设备的屏幕宽度。initial-scale=1.0
: 页面的初始缩放比例为 1.0,即不缩放。如果没有这行代码,移动端浏览器会默认使用一个桌面宽度的“虚拟视口”(通常是 980px)来渲染页面,然后将整个页面缩小,导致文字变得极小,布局混乱。
媒体查询是响应式设计的技术核心,它像一个 CSS 的 if
语句,允许我们为满足特定条件的设备应用特定的样式。
语法 : @media (媒体特性) { /* 在此条件满足时应用的 CSS 规则 */ }
常用媒体特性 描述 示例 min-width
当视口宽度 大于或等于 指定值时应用样式。 @media (min-width: 768px)
max-width
当视口宽度 小于或等于 指定值时应用样式。 @media (max-width: 767px)
orientation
portrait
(竖屏) 或 landscape
(横屏)。@media (orientation: landscape)
设计思想:移动优先 这是一种重要的现代响应式设计策略。我们不再先为大屏幕设计,再去“修补”小屏幕的样式。而是反过来:
先编写基础样式 : 这些样式服务于最小的设备(手机),保证核心功能和内容的完美呈现。这些代码写在所有 @media
规则之外。逐步增强 : 使用 min-width
媒体查询,为更大的屏幕(如平板、桌面)追加 更复杂的样式和布局。“移动优先”的优势 :性能更佳 : 移动设备只需加载最核心、最轻量的 CSS。代码更清晰 : 避免了在媒体查询中大量重置和覆盖桌面端样式,代码逻辑是不断“增加”而非“修改”。体验更专注 : 强迫我们优先考虑移动端用户的核心体验。6.5.2. 断点的选择 “断点”是指布局发生显著变化的屏幕宽度临界点。选择哪些断点并没有绝对的标准,最佳实践是根据你的内容 来决定在何时需要改变布局。不过,业界通常会参考一些主流 UI 框架(如 Bootstrap)的约定,这有助于团队协作。
一套常用的断点参考 :
设备类型 断点 描述 手机 (Mobile) < 768px
默认样式,通常为单列布局。 平板 (Tablet) ≥ 768px
布局开始变为多列,空间更宽裕。 桌面 (Desktop) ≥ 992px
经典的桌面端宽屏布局。 大桌面 (Large Desktop) ≥ 1200px
为超宽屏幕提供更丰富的布局。
6.5.3. 实战:将 Grid 首页布局改造为响应式 任务 : 我们将以 6.2.3
节中创建的经典网站布局为基础,采用“移动优先”的策略,为其添加响应式能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 响应式 Grid 布局</title > <style > body { margin : 0 ; font-family : sans-serif; } .responsive-layout { display : grid; min-height : 100vh ; gap : 10px ; grid-template-areas : "header" "main" "sidebar" "footer" ; grid-template-columns : 1 fr; grid-template-rows : 60px 1 fr auto 60px ; } @media (min-width : 768px ) { .responsive-layout { grid-template-areas : "header header" "sidebar main" "footer footer" ; grid-template-rows : 60px 1 fr 60px ; grid-template-columns : 200px 1 fr; } } .r-header { grid-area : header; background-color : #add8e6 ; } .r-sidebar { grid-area : sidebar; background-color : #b0e0e6 ; } .r-main { grid-area : main; background-color : #f0f8ff ; } .r-footer { grid-area : footer; background-color : #add8e6 ; } .r-header , .r-sidebar , .r-main , .r-footer { display : grid; place-items : center; font-size : 20px ;} </style > </head > <body > <div class ="responsive-layout" > <header class ="r-header" > Header</header > <aside class ="r-sidebar" > Sidebar</aside > <main class ="r-main" > Main Content</main > <footer class ="r-footer" > Footer</footer > </div > </body > </html >
请尝试在此将代码复制到Vs Code中,启用 F12 浏览器 拉动浏览器窗口查看效果
6.6. 最后的拼图:理解 Float 摘要 : 在本章的最后,我们将回顾一个在 CSS 历史上扮演过重要角色、但如今已回归其本职的属性——float
。本节的目标不是让您用它来构建复杂的布局,恰恰相反,是让您理解它的唯一正确应用场景 (图文环绕),并能看懂和维护那些使用浮动布局的“历史遗留”代码。我们将重点讲解浮动带来的“高度塌陷”问题以及经典的“清除浮动”解决方案。
6.6.1. Float 的唯一正确用途:图文环绕 float
属性最初被设计出来的唯一目的,就是为了实现类似报纸、杂志中的图文环绕排版效果。通过设置 float: left;
或 float: right;
,可以让一个元素(通常是图片)脱离正常的文档流,移动到其容器的左侧或右侧,其后的文本内容则会环绕在该元素的周围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <style > .article-content { width : 80% ; margin : auto; border : 1px solid #ccc ; padding : 20px ; font-family : sans-serif; line-height : 1.7 ; } .article-content img { float : left; margin-right : 20px ; margin-bottom : 10px ; border-radius : 8px ; } </style > <div class ="article-content" > <img src ="https://picsum.photos/seed/float-demo/200/200" alt ="Scenery" > <p > 这段文字将优雅地环绕在图片的周围。浮动(Float)最初就是为了实现这种类似报纸和杂志的图文混排效果而设计的。在现代 CSS 布局中,除了这个场景,我们几乎不再需要使用它。当一个元素浮动后,它会部分地脱离文档流,允许其他行内内容(如文本)围绕它流动。这是它最核心、也是如今唯一推荐的用途。</p > <p > 然而,开发者们曾“滥用”浮动来实现多列布局,但这会带来一系列的副作用,其中最著名的就是“高度塌陷”问题,我们将在下一节探讨它。</p > </div >
6.6.2. 历史遗留问题与解决方案:清除浮动 **问题:高度塌陷 ** 痛点背景 :当一个父元素内部的所有子元素都设置了浮动时,这些子元素会完全脱离常规文档流。对于父元素来说,它会认为自己“内部没有任何内容”,因此它的高度就会“塌陷”为 0。这将彻底打乱后续元素的布局。
直观演示 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <style > .parent-box { border : 3px solid #e74c3c ; width : 100% ; } .parent-box .child { float : left; width : 100px ; height : 100px ; background : #fbe9e7 ; margin : 10px ; } .next-element { margin-top : 20px ; background : #e3f2fd ; padding : 10px ; } </style > <div class ="parent-box" > <div class ="child" > Child 1</div > <div class ="child" > Child 2</div > </div > <div class ="next-element" > 我是父元素后面的元素。看,父元素的红色边框塌陷了,我的位置也乱了。 </div >
解决方案:清除浮动 为了解决高度塌陷问题,开发者们创造了多种“清除浮动”的方法。在 2025 年的今天,最常用且最标准的方法是 Clearfix Hack 。
它的原理是:利用 ::after
伪元素,在父元素的内容之后 添加一个看不见的、块级的、并且设置了 clear: both;
的虚拟元素。clear: both;
这条规则会命令这个虚拟元素“移动到所有浮动元素的下方”,从而迫使父元素必须将高度延伸到这个虚拟元素所在的位置,也就奇迹般地“撑开”了父元素。
标准 Clearfix 代码 :
1 2 3 4 5 6 7 .clearfix ::after { content : "" ; display : block; clear : both; height : 0 ; visibility : hidden; }
修复后的代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <style > .clearfix ::after { content : "" ; display : block; clear : both; } .parent-box-fixed { border : 3px solid #2ecc71 ; width : 100% ; } .parent-box-fixed .child { float : left; width : 100px ; height : 100px ; background : #e8f5e9 ; margin : 10px ; } .next-element-fixed { margin-top : 20px ; background : #e3f2fd ; padding : 10px ; } </style > <div class ="parent-box-fixed clearfix" > <div class ="child" > Child 1</div > <div class ="child" > Child 2</div > </div > <div class ="next-element-fixed" > 现在父元素的绿色边框正常了,我的位置也正确了。 </div >
现代视角 : Clearfix 的整个概念虽然巧妙,但也体现了使用 float
进行布局的复杂性和脆弱性。这正是我们现在拥抱 Flexbox 和 Grid 的根本原因——它们从设计上就避免了这类问题,让布局变得简单、直观和健壮。