03.CSS与响应式设计

1. CSS是什么?为什么需要它?

1.1 从"白纸"到"彩色画":HTML与CSS的关系

还记得我们在第二章学的HTML吗?HTML就像是一张白纸上的文字,告诉你"这里有个标题"、"那里有段文字",但所有的文字都是黑色、同样大小、没有颜色

生活类比: - HTML = 房子的框架结构(墙、门、窗) - CSS = 房子的装修风格(墙纸颜色、家具摆放、灯光效果)

实际例子

只有HTML的网页(像白纸):

1
2
3
<h1>我的博客</h1>
<p>欢迎来到我的网站</p>
<p>这里有很多有趣的内容</p>

加上CSS后的网页(像彩色画):

1
2
3
<h1 style="color: blue; font-size: 32px;">我的博客</h1>
<p style="color: gray; line-height: 1.6;">欢迎来到我的网站</p>
<p style="color: gray; line-height: 1.6;">这里有很多有趣的内容</p>

💡 关键理解
HTML负责"内容是什么",CSS负责"内容长什么样"。
就像写作文:HTML是"写什么",CSS是"怎么写漂亮"。


1.2 CSS的诞生:从"混乱"到"统一"

历史背景(1990s-1996)

在CSS出现之前,网页设计师们遇到了大麻烦:

问题 当时的解决方案 为什么不好
样式混乱 每个网站用不同的HTML标签实现样式 代码重复,维护困难
无法复用 每个页面都要重新写样式代码 改一个颜色要改100个地方
HTML臃肿 <font><center>等标签控制样式 HTML代码变得又长又乱

真实案例

1
2
3
4
5
<!-- 1990年代的网页代码(没有CSS) -->
<font color="red" size="5"><center><b>欢迎来到我的网站</b></center></font>
<font color="blue" size="3">这里有很多内容</font>
<font color="blue" size="3">还有更多内容</font>
<!-- 每个地方都要重复写样式,改颜色要改100次! -->

CSS的诞生(1996年)

1996年,W3C(万维网联盟)发布了CSS 1.0,彻底改变了网页设计:

CSS的优势 说明 实际效果
样式分离 样式写在单独的CSS文件中 HTML代码变简洁,CSS代码可复用
统一管理 改一个CSS文件,全站样式都变 改颜色只需改1个地方
专业分工 前端设计师专注CSS,后端专注HTML 开发效率提升10倍

现代代码(有CSS)

1
2
3
4
<!-- HTML:只负责结构 -->
<h1>欢迎来到我的网站</h1>
<p>这里有很多内容</p>
<p>还有更多内容</p>

1
2
3
4
5
6
7
8
9
10
11
/* CSS:统一管理样式 */
h1 {
color: red;
font-size: 32px;
text-align: center;
}
p {
color: blue;
font-size: 16px;
}
/* 改颜色?改这里就行! */

🌟 历史意义
CSS的诞生让网页设计从"手工作坊"变成了"现代化工厂",是Web开发史上的重要里程碑。


1.3 为什么CSS对现代Web开发至关重要?

重要性 说明 实际案例
用户体验 美观的界面吸引用户 同样功能的网站,设计好的访问量高3倍
维护效率 统一管理样式,修改方便 改主题颜色从"改100个文件"变成"改1个文件"
响应式设计 让网页适配手机、平板、电脑 一个网站,所有设备都能看
性能优化 CSS可以缓存,加载更快 用户第二次访问时,页面加载快50%

💡 对初学者的意义
学会CSS,你就能做出专业、美观、现代的网页。
这是从"能写代码"到"能做好看的产品"的关键一步!


2. CSS选择器:精准定位的"瞄准镜"

2.1 什么是选择器?

生活类比
想象你是一个园丁,花园里有100朵花,你想给"红色的玫瑰花"浇水。

  • 没有选择器:你只能一朵一朵地找,找到红色玫瑰再浇水(效率低)
  • 有选择器:你直接说"给所有红色玫瑰浇水",系统自动找到所有符合条件的(效率高)

CSS选择器 = 告诉浏览器"我要给哪些元素加样式"


2.2 基础选择器(必须掌握)

2.2.1 标签选择器(元素选择器)

作用:选中所有相同标签的元素

语法:直接写标签名

1
2
3
4
5
6
7
8
9
/* 选中所有 <p> 标签 */
p {
color: blue;
}

/* 选中所有 <h1> 标签 */
h1 {
font-size: 32px;
}

实际例子

1
2
3
<p>这是第一段</p>
<p>这是第二段</p>
<h1>这是标题</h1>

效果:所有<p>标签的文字变成蓝色,所有<h1>标签的字号变成32px

💡 适用场景:给所有相同类型的元素设置统一样式(比如所有段落都用同样的字体大小)


2.2.2 类选择器(最常用)

作用:选中所有具有相同class属性的元素

语法.类名(注意前面有个点)

1
2
3
4
5
6
7
8
9
10
11
/* 选中所有 class="highlight" 的元素 */
.highlight {
background-color: yellow;
}

/* 选中所有 class="button" 的元素 */
.button {
background-color: blue;
color: white;
padding: 10px;
}

实际例子

1
2
3
<p class="highlight">这段文字会被高亮</p>
<p>这段文字不会被高亮</p>
<button class="button">点击我</button>

效果:只有class="highlight"的段落背景变黄,只有class="button"的按钮有蓝色背景

💡 为什么最常用?
因为可以精确控制:不是所有段落都要高亮,只有特定的才需要。
就像给特定的人发消息,而不是群发所有人。


2.2.3 ID选择器

作用:选中具有特定id属性的元素(注意:一个页面中,同一个id只能出现一次

语法#id名(注意前面有个井号)

1
2
3
4
5
6
7
8
9
10
11
/* 选中 id="header" 的元素 */
#header {
background-color: #333;
color: white;
}

/* 选中 id="footer" 的元素 */
#footer {
background-color: #f0f0f0;
padding: 20px;
}

实际例子

1
2
3
<header id="header">网站头部</header>
<main>主要内容</main>
<footer id="footer">网站底部</footer>

效果:只有id="header"的元素有深色背景,只有id="footer"的元素有浅色背景

⚠️ 重要提醒
- ID是唯一的:一个页面中,同一个id只能出现一次(就像身份证号,每个人只有一个)
- 类可以重复:一个页面中,同一个class可以出现多次(就像"学生"这个身份,很多人都有)
- 什么时候用ID?:页面中唯一的元素(如header、footer、导航栏)
- 什么时候用类?:页面中可能重复的元素(如按钮、卡片、列表项)


2.2.4 属性选择器

作用:根据元素的属性及其值来选中元素

语法[属性名="属性值"]

1
2
3
4
5
6
7
8
9
/* 选中所有 type="text" 的输入框 */
input[type="text"] {
border: 1px solid #ccc;
}

/* 选中所有 href 属性包含 "http" 的链接 */
a[href*="http"] {
color: blue;
}

实际例子

1
2
3
4
<input type="text" placeholder="输入用户名">
<input type="password" placeholder="输入密码">
<a href="http://example.com">外部链接</a>
<a href="/about">内部链接</a>

效果:只有文本输入框有边框,只有外部链接是蓝色

💡 适用场景
当你想选中"具有特定属性的元素"时使用(比如所有外部链接、所有必填输入框)


2.3 组合选择器(进阶技巧)

2.3.1 后代选择器(空格)

作用:选中某个元素内部的所有指定元素(不管嵌套多少层)

语法父元素 子元素

1
2
3
4
/* 选中 .container 内部的所有 <p> 标签 */
.container p {
color: blue;
}

实际例子

1
2
3
4
5
6
7
<div class="container">
<p>这个段落会被选中</p>
<div>
<p>这个段落也会被选中(即使嵌套在div里)</p>
</div>
</div>
<p>这个段落不会被选中(不在.container里)</p>

效果:只有.container内部的段落变成蓝色,外部的段落不变


2.3.2 子元素选择器(>)

作用:选中某个元素的直接子元素(只选一层,不选嵌套的)

语法父元素 > 子元素

1
2
3
4
/* 只选中 .container 的直接子元素 <p> */
.container > p {
color: blue;
}

实际例子

1
2
3
4
5
6
<div class="container">
<p>这个段落会被选中(直接子元素)</p>
<div>
<p>这个段落不会被选中(不是直接子元素)</p>
</div>
</div>

对比: - 后代选择器(空格):选中所有嵌套的<p>(包括间接子元素) - 子元素选择器(>):只选中直接子元素<p>(不包括间接子元素)


2.3.3 并集选择器(逗号)

作用:同时选中多个不同的元素,给它们设置相同的样式

语法选择器1, 选择器2, 选择器3

1
2
3
4
5
/* 同时选中 h1、h2、h3,给它们设置相同的样式 */
h1, h2, h3 {
color: blue;
font-weight: bold;
}

实际例子

1
2
3
4
<h1>标题1</h1>
<h2>标题2</h2>
<h3>标题3</h3>
<p>段落</p>

效果:所有标题(h1、h2、h3)都变成蓝色加粗,段落不变


2.4 伪类选择器(让交互更生动)

什么是伪类?
伪类选择器用于选中元素的特定状态(比如鼠标悬停、被点击、第一个子元素等)

2.4.1 常用伪类

伪类 作用 示例
:hover 鼠标悬停时的状态 按钮悬停时变色
:active 鼠标点击时的状态 按钮按下时的效果
:focus 元素获得焦点时 输入框被选中时
:first-child 第一个子元素 列表第一项特殊样式
:nth-child(n) 第n个子元素 列表奇数项特殊样式

实际例子

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
/* 链接默认样式 */
a {
color: blue;
text-decoration: none;
}

/* 鼠标悬停时 */
a:hover {
color: red;
text-decoration: underline;
}

/* 鼠标点击时 */
a:active {
color: green;
}

/* 列表第一项 */
li:first-child {
font-weight: bold;
}

/* 列表奇数项 */
li:nth-child(odd) {
background-color: #f0f0f0;
}

HTML示例

1
2
3
4
5
6
7
<a href="#">点击我试试</a>
<ul>
<li>第一项(会加粗)</li>
<li>第二项</li>
<li>第三项(会有背景色)</li>
<li>第四项</li>
</ul>

效果: - 链接默认蓝色,鼠标悬停变红色并加下划线,点击时变绿色 - 列表第一项加粗,奇数项有浅灰色背景

💡 为什么叫"伪类"?
因为它不是真正的HTML类(class),而是元素的"状态"。
就像人的"状态":健康、生病、疲劳,不是人的属性,而是某个时刻的状态。


2.5 选择器优先级(重要概念)

2.5.1 什么是优先级?

当多个选择器选中同一个元素,且设置了不同的样式时,浏览器需要决定"听谁的"。

优先级规则(从高到低): 1. 内联样式style="...") - 优先级最高 2. ID选择器#id) 3. 类选择器.class)、属性选择器([attr])、伪类(:hover) 4. 标签选择器pdiv等)

实际例子

1
<p class="text" id="intro" style="color: green;">这是一段文字</p>

1
2
3
4
5
6
7
8
9
10
p {
color: blue; /* 优先级:1(标签选择器) */
}
.text {
color: red; /* 优先级:10(类选择器) */
}
#intro {
color: yellow; /* 优先级:100(ID选择器) */
}
/* 但内联样式 style="color: green;" 优先级最高:1000 */

最终效果:文字是绿色(因为内联样式优先级最高)

💡 记忆技巧
优先级就像"权力等级":
- 内联样式 = 皇帝(最高权力)
- ID选择器 = 大臣(高权力)
- 类选择器 = 官员(中等权力)
- 标签选择器 = 平民(基础权力)


2.6 实战练习:用选择器美化页面

任务:给下面的HTML添加CSS,实现以下效果: - 所有段落文字为灰色 - 所有.highlight类的元素背景为黄色 - 所有链接默认蓝色,悬停时变红色 - 列表第一项加粗

HTML代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
<title>选择器练习</title>
<style>
/* 在这里写CSS */
</style>
</head>
<body>
<h1>我的网页</h1>
<p>这是一段普通文字</p>
<p class="highlight">这是一段高亮文字</p>
<a href="#">点击我</a>
<ul>
<li>第一项</li>
<li>第二项</li>
<li>第三项</li>
</ul>
</body>
</html>

参考答案

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
/* 所有段落文字为灰色 */
p {
color: gray;
}

/* 所有 .highlight 类的元素背景为黄色 */
.highlight {
background-color: yellow;
}

/* 所有链接默认蓝色 */
a {
color: blue;
text-decoration: none;
}

/* 链接悬停时变红色 */
a:hover {
color: red;
}

/* 列表第一项加粗 */
li:first-child {
font-weight: bold;
}

🌟 记住
选择器是CSS的"瞄准镜",学会精准定位,你就能控制网页的每一个细节!


3. Flex布局实战:让元素"听话"的魔法

3.1 为什么需要Flex布局?

3.1.1 传统布局的痛点

还记得我们之前学的HTML吗?当我们把几个<div>放在一起时,它们会垂直排列(一个在另一个下面),就像叠积木一样。

问题来了:如果我们想让它们横向排列(并排显示),比如做一个导航栏,该怎么办?

传统方法(很麻烦):

1
2
3
4
5
6
7
8
9
10
11
/* 方法1:使用float(浮动) */
.nav-item {
float: left; /* 让元素"浮起来",横向排列 */
}
/* 问题:需要清除浮动,容易出bug */

/* 方法2:使用inline-block */
.nav-item {
display: inline-block; /* 让块级元素变成行内块 */
}
/* 问题:元素之间会有空隙,难以控制 */

💡 生活类比
传统布局就像"手动摆积木":
- 想横向排列?得用各种"技巧"(float、inline-block)
- 想居中?得算数学(margin: 0 auto)
- 想对齐?得写很多代码

Flex布局就像"智能积木盒":
- 说一句"横向排列",所有积木自动排好
- 说一句"居中",自动居中
- 简单、直观、强大!


3.1.2 Flex布局的诞生(2012年)

2012年,W3C正式发布了Flexbox布局规范,彻底改变了CSS布局方式:

传统布局 Flex布局
需要写很多代码 几行代码搞定
容易出bug(如浮动塌陷) 稳定可靠
难以实现复杂对齐 轻松实现各种对齐
响应式适配困难 天然支持响应式

🌟 历史意义
Flex布局是CSS布局史上的革命性突破,让"居中"、"对齐"这些曾经让人头疼的问题,变得像写一句话那么简单。


3.2 Flex布局的核心概念

3.2.1 什么是Flex容器和Flex项目?

生活类比
想象一个收纳盒(Flex容器),里面放着几个小盒子(Flex项目)。

  • Flex容器:设置了display: flex;的元素(就像收纳盒)
  • Flex项目:Flex容器内的直接子元素(就像小盒子)

实际例子

1
2
3
4
5
<div class="container">  <!-- 这是Flex容器 -->
<div class="item">项目1</div> <!-- 这是Flex项目 -->
<div class="item">项目2</div> <!-- 这是Flex项目 -->
<div class="item">项目3</div> <!-- 这是Flex项目 -->
</div>

1
2
3
.container {
display: flex; /* 让.container变成Flex容器 */
}

⚠️ 重要提醒
只有直接子元素才是Flex项目!
如果.container里面有个<div><div>里面又有<p>,那么<p>不是Flex项目(因为不是直接子元素)。


3.2.2 主轴和交叉轴:Flex布局的"坐标系"

生活类比
想象你在整理书架: - 主轴 = 书架的横向(从左到右,或从右到左) - 交叉轴 = 书架的纵向(从上到下,或从下到上)

Flex布局中的两个轴

默认方向 作用 类比
主轴(Main Axis) 水平方向(从左到右) 控制Flex项目的排列方向 书架的横向
交叉轴(Cross Axis) 垂直方向(从上到下) 控制Flex项目的对齐方式 书架的纵向

示意图

1
2
3
4
5
6
7
主轴(Main Axis)→→→→→→→→→→→→→


交叉轴
(Cross Axis)


💡 记忆技巧
- 主轴 = 主要排列方向(横向或纵向)
- 交叉轴 = 垂直于主轴的方向
- 默认情况下,主轴是横向,交叉轴是纵向


3.3 Flex布局的常用属性(必须掌握)

3.3.1 容器的属性(在Flex容器上设置)

1. display: flex; - 开启Flex布局

作用:让元素变成Flex容器

语法

1
2
3
.container {
display: flex; /* 开启Flex布局 */
}

实际例子

1
2
3
4
5
<div class="box">
<div>项目1</div>
<div>项目2</div>
<div>项目3</div>
</div>

1
2
3
.box {
display: flex; /* 三个div会横向排列 */
}

效果:三个<div>横向排列(并排显示),而不是垂直排列。


2. flex-direction - 控制主轴方向

作用:决定Flex项目沿着哪个方向排列

可选值

效果 主轴方向
row(默认) 横向排列(从左到右) 水平
row-reverse 横向排列(从右到左) 水平(反向)
column 纵向排列(从上到下) 垂直
column-reverse 纵向排列(从下到上) 垂直(反向)

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
.container {
display: flex;
flex-direction: row; /* 横向排列(默认值) */
/* 项目1 | 项目2 | 项目3 */
}

.container {
display: flex;
flex-direction: column; /* 纵向排列 */
/* 项目1
项目2
项目3 */
}

💡 生活类比
flex-direction就像决定"书架是横着放还是竖着放": - row = 横着放(书从左到右排列) - column = 竖着放(书从上到下排列)


3. justify-content - 主轴对齐方式

作用:控制Flex项目在主轴上的对齐方式(这是最常用的属性之一!)

可选值

效果 示意图
flex-start(默认) 从主轴起点开始排列 [项目1][项目2][项目3]
flex-end 从主轴终点开始排列 [项目1][项目2][项目3]
center 在主轴上居中 [项目1][项目2][项目3]
space-between 项目之间平均分布,首尾贴边 [项目1] [项目2] [项目3]
space-around 项目周围平均分布 [项目1] [项目2] [项目3]
space-evenly 项目之间完全平均分布 [项目1] [项目2] [项目3]

实际例子

1
2
3
4
.container {
display: flex;
justify-content: center; /* 项目在主轴上居中 */
}

效果对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 左对齐 */
justify-content: flex-start;
/* [项目1][项目2][项目3] */

/* 居中 */
justify-content: center;
/* [项目1][项目2][项目3] */

/* 右对齐 */
justify-content: flex-end;
/* [项目1][项目2][项目3] */

/* 平均分布(首尾贴边) */
justify-content: space-between;
/* [项目1] [项目2] [项目3] */

💡 记忆技巧
justify-content = "主轴对齐"
想居中?用center
想平均分布?用space-between


4. align-items - 交叉轴对齐方式

作用:控制Flex项目在交叉轴上的对齐方式

可选值

效果 说明
stretch(默认) 拉伸填满容器 项目会被拉伸到容器高度
flex-start 从交叉轴起点对齐 项目靠上对齐
flex-end 从交叉轴终点对齐 项目靠下对齐
center 在交叉轴上居中 最常用! 垂直居中
baseline 基线对齐 文字基线对齐

实际例子

1
2
3
4
.container {
display: flex;
align-items: center; /* 项目在交叉轴上居中(垂直居中) */
}

效果对比(假设容器高度是100px):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 靠上对齐 */
align-items: flex-start;
/* [项目1]
[项目2]
[项目3] */

/* 垂直居中 */
align-items: center;
/* [项目1]
[项目2]
[项目3] */

/* 靠下对齐 */
align-items: flex-end;
/* [项目1]
[项目2]
[项目3] */

💡 最常用场景
想实现垂直居中?用align-items: center;
这是Flex布局最强大的功能之一,以前需要写很多代码才能实现,现在一行搞定!


5. gap - 项目之间的间距

作用:设置Flex项目之间的间距(注意:这是较新的属性,现代浏览器都支持

语法

1
2
3
4
.container {
display: flex;
gap: 20px; /* 项目之间间距20px */
}

实际例子

1
2
3
4
.container {
display: flex;
gap: 15px; /* 所有项目之间都有15px的间距 */
}

效果

1
[项目1] --15px-- [项目2] --15px-- [项目3]

💡 为什么推荐用gap
以前设置间距需要用margin,但margin会有很多问题(比如首尾项目也会有外边距)。
gap属性专门用来设置项目间距,简单、直观、不会出错


3.3.2 项目的属性(在Flex项目上设置)

flex - 控制项目的伸缩比例

作用:控制Flex项目如何分配剩余空间

语法

1
2
3
.item {
flex: 1; /* 平均分配剩余空间 */
}

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.container {
display: flex;
}

.item1 {
flex: 1; /* 占1份 */
}

.item2 {
flex: 2; /* 占2份(是item1的2倍宽) */
}

.item3 {
flex: 1; /* 占1份 */
}

效果item2的宽度是item1item3的2倍。

💡 生活类比
flex就像"分蛋糕": - flex: 1 = 分1份 - flex: 2 = 分2份(是1份的2倍) - flex: 3 = 分3份(是1份的3倍)


3.4 实战案例:实现导航栏布局

3.4.1 需求分析

我们要做一个导航栏,包含: - 左侧:网站Logo - 右侧:导航链接(首页、关于、服务、联系)

布局要求: - Logo在左边,导航链接在右边 - 导航链接横向排列 - 所有内容垂直居中


3.4.2 HTML结构

1
2
3
4
5
6
7
8
9
<header class="navbar">
<div class="logo">我的网站</div>
<nav class="nav-links">
<a href="#">首页</a>
<a href="#">关于</a>
<a href="#">服务</a>
<a href="#">联系</a>
</nav>
</header>

3.4.3 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
/* 导航栏容器:使用Flex布局 */
.navbar {
display: flex; /* 开启Flex布局 */
justify-content: space-between; /* Logo在左,导航在右 */
align-items: center; /* 垂直居中 */
padding: 15px 30px; /* 内边距 */
background-color: #333; /* 深色背景 */
}

/* Logo样式 */
.logo {
color: white;
font-size: 24px;
font-weight: bold;
}

/* 导航链接容器:也需要Flex布局(让链接横向排列) */
.nav-links {
display: flex; /* 再次使用Flex布局 */
gap: 20px; /* 链接之间间距20px */
}

/* 导航链接样式 */
.nav-links a {
color: white;
text-decoration: none; /* 去除下划线 */
padding: 8px 16px; /* 内边距 */
border-radius: 4px; /* 圆角 */
transition: background-color 0.3s; /* 过渡效果 */
}

/* 链接悬停效果 */
.nav-links a:hover {
background-color: #555; /* 悬停时背景变深 */
}

3.4.4 代码解析(逐步理解)

第一步:让导航栏变成Flex容器

1
2
3
.navbar {
display: flex; /* 开启Flex布局 */
}

效果.navbar内的直接子元素(.logo.nav-links)会变成Flex项目,横向排列。

第二步:让Logo和导航链接分布在两端

1
2
3
.navbar {
justify-content: space-between; /* Logo在左,导航在右 */
}

效果:Logo靠左,导航链接靠右,中间留空。

第三步:垂直居中

1
2
3
.navbar {
align-items: center; /* 垂直居中 */
}

效果:Logo和导航链接在垂直方向上居中对齐。

第四步:让导航链接横向排列

1
2
3
4
.nav-links {
display: flex; /* 再次使用Flex布局 */
gap: 20px; /* 链接之间间距 */
}

效果:所有链接横向排列,之间有20px的间距。


3.4.5 最终效果

1
2
3
┌─────────────────────────────────────────┐
│ 我的网站 首页 关于 服务 联系 │
└─────────────────────────────────────────┘
  • ✅ Logo在左边
  • ✅ 导航链接在右边,横向排列
  • ✅ 所有内容垂直居中
  • ✅ 链接之间有间距
  • ✅ 悬停时有交互效果

3.5 更多实战案例

案例1:卡片布局(三列等宽)

需求:三个卡片横向排列,等宽,间距相等

HTML

1
2
3
4
5
<div class="card-container">
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
.card-container {
display: flex;
gap: 20px; /* 卡片之间间距 */
}

.card {
flex: 1; /* 每个卡片平均分配空间(等宽) */
padding: 20px;
background-color: #f0f0f0;
border-radius: 8px;
}

效果:三个卡片等宽,横向排列,间距20px。


案例2:居中布局(最常用!)

需求:让一个元素在页面中完全居中(水平和垂直都居中)

HTML

1
2
3
<div class="center-container">
<div class="content">我要居中!</div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
.center-container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 100vh; /* 容器高度为视口高度 */
}

.content {
padding: 20px;
background-color: #f0f0f0;
}

效果.content在页面中完全居中(水平和垂直都居中)。

🌟 这是Flex布局最强大的功能之一!
以前实现完全居中需要写很多代码,现在只需要3行CSS!


3.6 常见问题与解决方案

问题1:Flex项目没有横向排列?

可能原因: - 忘记写display: flex; - Flex项目被其他CSS样式覆盖

解决方案

1
2
3
.container {
display: flex; /* 确保写了这一行 */
}


问题2:想实现垂直排列?

解决方案

1
2
3
4
.container {
display: flex;
flex-direction: column; /* 改为纵向排列 */
}


问题3:项目之间的间距怎么设置?

解决方案

1
2
3
4
.container {
display: flex;
gap: 20px; /* 使用gap属性(推荐) */
}


3.7 本节总结

你已经学会了:

Flex布局的核心概念: - Flex容器和Flex项目 - 主轴和交叉轴

容器的常用属性: - display: flex; - 开启Flex布局 - flex-direction - 控制排列方向 - justify-content - 主轴对齐(水平对齐) - align-items - 交叉轴对齐(垂直对齐) - gap - 项目间距

项目的常用属性: - flex - 控制伸缩比例

实战技能: - 实现导航栏布局 - 实现卡片布局 - 实现居中布局

🌟 记住
Flex布局是现代Web开发的必备技能
掌握了Flex布局,你就能轻松实现90%的常见布局需求。
多练习,多实践,把Flex布局变成你的"肌肉记忆"!


4. 媒体查询应用:让网页"智能适配"

4.1 为什么需要媒体查询?

4.1.1 问题的出现:一个网页,多种设备

生活场景
想象你设计了一件衣服: - 在模特身上很好看(桌面电脑) - 但给小朋友穿就太大了(手机) - 给高个子穿又太小了(平板)

网页的困境: - 在电脑上:三列布局,看起来很舒服 - 在手机上:三列挤在一起,字太小,根本看不清 - 在平板上:布局不协调,体验很差

传统解决方案(很麻烦):

1
2
3
4
5
<!-- 方法1:为不同设备写不同的网页 -->
<!-- 电脑版:desktop.html -->
<!-- 手机版:mobile.html -->
<!-- 平板版:tablet.html -->
<!-- 问题:维护3个网站,成本太高! -->

💡 核心问题
一个网页,需要在不同尺寸的屏幕上都能正常显示。
就像一件衣服,要能适应不同身材的人。


4.1.2 媒体查询的诞生(2012年)

2012年,CSS3正式引入媒体查询(Media Queries),让一个网页可以"智能适配"不同设备:

传统方式 媒体查询方式
为每个设备写一个网页 一个网页,自动适配
维护成本高 维护成本低
用户体验差 用户体验好
加载慢(需要判断设备) 加载快(CSS自动判断)

🌟 历史意义
媒体查询让"响应式设计"成为可能,是现代Web开发的标准做法


4.2 什么是媒体查询?

4.2.1 生活类比

媒体查询就像"智能空调": - 温度>30°C → 自动开启制冷 - 温度<20°C → 自动开启制热 - 温度20-30°C → 自动关闭

媒体查询: - 屏幕宽度>768px → 应用桌面样式(三列布局) - 屏幕宽度<768px → 应用手机样式(单列布局) - 屏幕宽度768-1024px → 应用平板样式(两列布局)


4.2.2 媒体查询的定义

媒体查询 = CSS的"条件判断"
根据设备的特性(屏幕宽度、高度、方向等),应用不同的CSS样式。

基本语法

1
2
3
@media (条件) {
/* 当条件满足时,应用这些样式 */
}

实际例子

1
2
3
4
5
6
7
8
9
10
11
/* 默认样式(所有设备) */
.container {
display: flex;
}

/* 当屏幕宽度小于768px时,应用这些样式 */
@media (max-width: 768px) {
.container {
flex-direction: column; /* 改为纵向排列 */
}
}

效果: - 屏幕宽度 > 768px:.container内的元素横向排列 - 屏幕宽度 ≤ 768px:.container内的元素纵向排列


4.3 媒体查询的语法详解

4.3.1 基本语法结构

1
2
3
@media [媒体类型] and (条件) {
/* CSS样式 */
}

组成部分

部分 说明 示例
@media 媒体查询的关键字 必须写
媒体类型 设备类型(可选) screen(屏幕)、print(打印)
and 逻辑运算符 连接多个条件
(条件) 具体的判断条件 max-width: 768px

4.3.2 常用的媒体类型

媒体类型 说明 使用场景
screen 屏幕设备(默认) 电脑、手机、平板
print 打印设备 打印网页时
all 所有设备 不常用

实际例子

1
2
3
4
5
6
7
8
9
/* 屏幕设备 */
@media screen and (max-width: 768px) {
/* 样式 */
}

/* 打印设备 */
@media print {
/* 打印时的样式 */
}

💡 注意
大多数情况下,我们只需要写@media (条件),不需要写screen,因为默认就是屏幕设备。


4.3.3 常用的媒体特性(条件)

媒体特性 说明 示例
max-width 最大宽度(小于等于) max-width: 768px(宽度≤768px)
min-width 最小宽度(大于等于) min-width: 768px(宽度≥768px)
max-height 最大高度 max-height: 600px
min-height 最小高度 min-height: 600px
orientation 设备方向 orientation: portrait(竖屏)
orientation: landscape(横屏)

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 当屏幕宽度小于等于768px时 */
@media (max-width: 768px) {
body {
font-size: 14px;
}
}

/* 当屏幕宽度大于等于1024px时 */
@media (min-width: 1024px) {
body {
font-size: 18px;
}
}

/* 当设备是竖屏时 */
@media (orientation: portrait) {
.sidebar {
display: none; /* 隐藏侧边栏 */
}
}

💡 记忆技巧
- max-width: 768px = "宽度最多768px"(≤768px)
- min-width: 768px = "宽度至少768px"(≥768px)


4.4 响应式设计的断点(Breakpoint)

4.4.1 什么是断点?

生活类比
断点就像"温度计上的刻度": - 0°C → 结冰 - 100°C → 沸腾

响应式设计的断点: - 768px → 手机和电脑的分界线 - 1024px → 平板和电脑的分界线

断点 = 根据屏幕宽度,改变页面布局的"临界点"


4.4.2 常用的断点值

设备类型 屏幕宽度 常用断点
手机 < 768px max-width: 768px
平板 768px - 1024px min-width: 768pxmax-width: 1024px
电脑 > 1024px min-width: 1024px

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 手机样式(默认,移动优先) */
.container {
flex-direction: column; /* 单列布局 */
}

/* 平板样式(≥768px) */
@media (min-width: 768px) {
.container {
flex-direction: row; /* 两列布局 */
flex-wrap: wrap;
}
.item {
flex: 1 1 50%; /* 每个项目占50%宽度 */
}
}

/* 电脑样式(≥1024px) */
@media (min-width: 1024px) {
.item {
flex: 1 1 33.33%; /* 每个项目占33.33%宽度(三列) */
}
}


4.4.3 移动优先(Mobile First)策略

什么是移动优先?

传统方式(桌面优先):

1
2
3
4
5
6
7
8
9
10
11
/* 先写桌面样式 */
.container {
display: flex; /* 三列布局 */
}

/* 再用媒体查询覆盖(手机) */
@media (max-width: 768px) {
.container {
flex-direction: column; /* 单列布局 */
}
}

移动优先方式(推荐):

1
2
3
4
5
6
7
8
9
10
11
/* 先写手机样式(默认) */
.container {
flex-direction: column; /* 单列布局 */
}

/* 再用媒体查询增强(平板、电脑) */
@media (min-width: 768px) {
.container {
flex-direction: row; /* 横向布局 */
}
}

为什么推荐移动优先?

优势 说明
性能更好 手机用户先加载简单样式,加载更快
代码更简洁 从简单到复杂,逻辑更清晰
符合趋势 现在手机用户比电脑用户多

💡 记忆技巧
移动优先 = "先写手机样式,再用媒体查询增强"
就像"先搭好基础框架,再逐步完善"


4.5 实战案例:制作自适应页面

4.5.1 需求分析

我们要做一个响应式卡片布局: - 手机(< 768px):单列布局,卡片占满宽度 - 平板(768px - 1024px):两列布局 - 电脑(> 1024px):三列布局


4.5.2 HTML结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式卡片布局</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
<div class="card">卡片4</div>
<div class="card">卡片5</div>
<div class="card">卡片6</div>
</div>
</body>
</html>

⚠️ 重要提醒
必须在<head>中添加:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0">
这行代码告诉浏览器"按设备宽度显示",没有这行,媒体查询可能不生效!


4.5.3 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
/* ===== 基础样式(手机,移动优先) ===== */
body {
margin: 0;
padding: 20px;
font-family: '微软雅黑', Arial, sans-serif;
}

.container {
display: flex;
flex-direction: column; /* 手机:单列布局 */
gap: 20px;
}

.card {
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* ===== 平板样式(≥768px) ===== */
@media (min-width: 768px) {
.container {
flex-direction: row; /* 改为横向排列 */
flex-wrap: wrap; /* 允许换行 */
}

.card {
flex: 1 1 calc(50% - 10px); /* 每个卡片占50%宽度(两列) */
/* calc(50% - 10px) 是为了减去gap的一半 */
}
}

/* ===== 电脑样式(≥1024px) ===== */
@media (min-width: 1024px) {
.card {
flex: 1 1 calc(33.33% - 14px); /* 每个卡片占33.33%宽度(三列) */
}
}

4.5.4 代码解析(逐步理解)

第一步:手机样式(默认)

1
2
3
4
5
.container {
display: flex;
flex-direction: column; /* 单列布局 */
gap: 20px;
}

效果:所有卡片垂直排列,每个卡片占满宽度。

第二步:平板样式(≥768px)

1
2
3
4
5
6
7
8
9
10
@media (min-width: 768px) {
.container {
flex-direction: row; /* 改为横向排列 */
flex-wrap: wrap; /* 允许换行 */
}

.card {
flex: 1 1 calc(50% - 10px); /* 两列布局 */
}
}

效果:卡片横向排列,每行显示2个卡片。

第三步:电脑样式(≥1024px)

1
2
3
4
5
@media (min-width: 1024px) {
.card {
flex: 1 1 calc(33.33% - 14px); /* 三列布局 */
}
}

效果:每行显示3个卡片。


4.5.5 最终效果

手机(< 768px)

1
2
3
4
5
6
7
8
9
┌─────────────┐
│ 卡片1 │
└─────────────┘
┌─────────────┐
│ 卡片2 │
└─────────────┘
┌─────────────┐
│ 卡片3 │
└─────────────┘

平板(768px - 1024px)

1
2
3
4
5
6
┌──────────┐ ┌──────────┐
│ 卡片1 │ │ 卡片2 │
└──────────┘ └──────────┘
┌──────────┐ ┌──────────┐
│ 卡片3 │ │ 卡片4 │
└──────────┘ └──────────┘

电脑(> 1024px)

1
2
3
4
5
6
┌────────┐ ┌────────┐ ┌────────┐
│ 卡片1 │ │ 卡片2 │ │ 卡片3 │
└────────┘ └────────┘ └────────┘
┌────────┐ ┌────────┐ ┌────────┐
│ 卡片4 │ │ 卡片5 │ │ 卡片6 │
└────────┘ └────────┘ └────────┘


4.6 更多实战案例

案例1:响应式导航栏

需求:电脑上显示横向导航,手机上显示汉堡菜单

HTML

1
2
3
4
5
6
7
8
9
10
<nav class="navbar">
<div class="logo">我的网站</div>
<ul class="nav-menu">
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系</a></li>
</ul>
<button class="menu-toggle"></button>
</nav>

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
/* 手机样式(默认) */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
}

.nav-menu {
display: none; /* 手机:隐藏菜单 */
}

.menu-toggle {
display: block; /* 手机:显示汉堡按钮 */
}

/* 电脑样式(≥768px) */
@media (min-width: 768px) {
.nav-menu {
display: flex; /* 电脑:显示菜单 */
gap: 20px;
list-style: none;
}

.menu-toggle {
display: none; /* 电脑:隐藏汉堡按钮 */
}
}


案例2:响应式字体大小

需求:根据屏幕宽度调整字体大小

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 手机:小字体 */
body {
font-size: 14px;
}

/* 平板:中等字体 */
@media (min-width: 768px) {
body {
font-size: 16px;
}
}

/* 电脑:大字体 */
@media (min-width: 1024px) {
body {
font-size: 18px;
}
}


4.7 常见问题与解决方案

问题1:媒体查询不生效?

可能原因: 1. 忘记添加viewport元标签 2. 媒体查询语法错误 3. CSS优先级问题

解决方案

1
2
<!-- 1. 确保HTML中有这行 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

1
2
3
4
5
6
7
8
9
10
11
/* 2. 检查语法是否正确 */
@media (max-width: 768px) { /* 注意:括号和冒号 */
/* 样式 */
}

/* 3. 如果还是不生效,提高优先级 */
@media (max-width: 768px) {
.container.container { /* 重复类名提高优先级 */
flex-direction: column;
}
}

问题2:断点值应该选多少?

推荐断点(根据主流设备): - 手机max-width: 767pxmax-width: 575px - 平板min-width: 768pxmax-width: 1023px - 电脑min-width: 1024px

实际建议: - 不要设置太多断点(3-4个足够) - 根据实际内容调整,不要死记硬背 - 使用浏览器开发者工具测试(F12 → 设备工具栏)


问题3:移动优先还是桌面优先?

推荐:移动优先

原因: - 手机用户更多 - 性能更好(先加载简单样式) - 代码更简洁(从简单到复杂)

写法

1
2
3
4
5
6
7
8
9
10
11
/* 移动优先:先写手机样式 */
.container {
/* 手机样式 */
}

/* 再用媒体查询增强 */
@media (min-width: 768px) {
.container {
/* 平板/电脑样式 */
}
}


4.8 本节总结

你已经学会了:

媒体查询的核心概念: - 什么是媒体查询 - 为什么需要媒体查询

媒体查询的语法: - 基本语法结构 - 常用的媒体类型和特性 - max-widthmin-width的区别

响应式设计策略: - 断点的概念 - 移动优先策略 - 常用断点值

实战技能: - 制作自适应页面布局 - 响应式导航栏 - 响应式字体大小

🌟 记住
媒体查询是实现响应式设计的核心工具
掌握了媒体查询,你就能让网页在各种设备上都有良好的体验。
一个网页,适配所有设备,这就是现代Web开发的魅力!


5. AI实战:使用AI生成响应式布局

5.1 为什么用AI生成响应式布局?

5.1.1 响应式布局的复杂性

还记得我们刚才学的媒体查询吗?要实现一个完整的响应式布局,需要: - 写基础样式(手机) - 写平板样式(媒体查询) - 写电脑样式(媒体查询) - 测试不同设备 - 调试各种问题

工作量:一个简单的响应式页面,可能需要写100+行CSS代码。


5.1.2 AI的优势

AI可以帮你: - ✅ 快速生成完整的响应式布局代码 - ✅ 自动处理不同设备的适配 - ✅ 生成符合最佳实践的代码 - ✅ 节省大量时间

你的工作: - ✅ 描述需求(写Prompt) - ✅ 测试效果 - ✅ 微调细节

💡 生活类比
以前:自己画设计图 → 自己写代码 → 自己调试(3天)
现在:告诉AI需求 → AI生成代码 → 你测试调整(3小时)


5.2 实战案例:用AI生成响应式导航栏

5.2.1 第一步:设计Prompt

目标:生成一个响应式导航栏

Prompt示例

1
2
3
4
5
6
7
用HTML和CSS创建一个响应式导航栏,要求:
1. 包含Logo(左侧)和导航链接(右侧)
2. 电脑上:横向显示所有链接
3. 手机上:显示汉堡菜单按钮,点击后展开菜单
4. 使用Flex布局和媒体查询
5. 样式现代化,有悬停效果
6. 代码注释清晰


5.2.2 AI生成的代码(示例)

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式导航栏</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav class="navbar">
<div class="logo">我的网站</div>
<ul class="nav-menu" id="navMenu">
<li><a href="#">首页</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系</a></li>
</ul>
<button class="menu-toggle" id="menuToggle"></button>
</nav>
</body>
</html>

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
/* ===== 基础样式 ===== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background-color: #333;
}

.logo {
color: white;
font-size: 24px;
font-weight: bold;
}

.nav-menu {
display: flex;
list-style: none;
gap: 30px;
}

.nav-menu a {
color: white;
text-decoration: none;
padding: 8px 16px;
border-radius: 4px;
transition: background-color 0.3s;
}

.nav-menu a:hover {
background-color: #555;
}

.menu-toggle {
display: none; /* 电脑上隐藏 */
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
}

/* ===== 手机样式(≤768px) ===== */
@media (max-width: 768px) {
.nav-menu {
position: fixed;
top: 60px;
left: -100%; /* 默认隐藏 */
width: 100%;
flex-direction: column;
background-color: #333;
padding: 20px;
transition: left 0.3s;
}

.nav-menu.active {
left: 0; /* 展开时显示 */
}

.menu-toggle {
display: block; /* 手机上显示 */
}
}

JavaScript(AI可能也会生成):

1
2
3
4
// 切换菜单显示/隐藏
document.getElementById('menuToggle').addEventListener('click', function() {
document.getElementById('navMenu').classList.toggle('active');
});


5.2.3 测试和优化

测试步骤: 1. 在浏览器中打开页面 2. 按F12打开开发者工具 3. 点击"设备工具栏"图标(或按Ctrl+Shift+M) 4. 选择不同设备测试(iPhone、iPad、Desktop)

可能需要的优化: - 调整断点值 - 修改颜色和间距 - 优化动画效果


5.3 实战案例:用AI生成响应式卡片布局

5.3.1 Prompt设计

1
2
3
4
5
6
7
8
用HTML和CSS创建一个响应式卡片布局,要求:
1. 使用Flex布局
2. 手机:单列布局,卡片占满宽度
3. 平板:两列布局
4. 电脑:三列布局
5. 使用移动优先策略
6. 卡片有阴影和圆角效果
7. 代码注释清晰,使用媒体查询

5.3.2 AI生成的代码(优化版)

HTML

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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式卡片布局</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="card">
<h3>卡片标题1</h3>
<p>这是卡片的内容描述...</p>
</div>
<div class="card">
<h3>卡片标题2</h3>
<p>这是卡片的内容描述...</p>
</div>
<div class="card">
<h3>卡片标题3</h3>
<p>这是卡片的内容描述...</p>
</div>
<div class="card">
<h3>卡片标题4</h3>
<p>这是卡片的内容描述...</p>
</div>
<div class="card">
<h3>卡片标题5</h3>
<p>这是卡片的内容描述...</p>
</div>
<div class="card">
<h3>卡片标题6</h3>
<p>这是卡片的内容描述...</p>
</div>
</div>
</body>
</html>

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
/* ===== 基础样式(手机,移动优先) ===== */
body {
margin: 0;
padding: 20px;
font-family: '微软雅黑', Arial, sans-serif;
background-color: #f5f5f5;
}

.container {
display: flex;
flex-direction: column; /* 手机:单列布局 */
gap: 20px;
max-width: 1200px;
margin: 0 auto;
}

.card {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
}

.card:hover {
transform: translateY(-5px); /* 悬停时上移 */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.card h3 {
margin-top: 0;
color: #333;
}

.card p {
color: #666;
line-height: 1.6;
}

/* ===== 平板样式(≥768px) ===== */
@media (min-width: 768px) {
.container {
flex-direction: row; /* 改为横向排列 */
flex-wrap: wrap; /* 允许换行 */
}

.card {
flex: 1 1 calc(50% - 10px); /* 两列布局 */
}
}

/* ===== 电脑样式(≥1024px) ===== */
@media (min-width: 1024px) {
.card {
flex: 1 1 calc(33.33% - 14px); /* 三列布局 */
}
}


5.4 AI生成代码的优化技巧

5.4.1 如何写出更好的Prompt?

不好的Prompt

1
写一个响应式布局
问题:太模糊,AI不知道具体需求

好的Prompt

1
2
3
4
5
6
7
用HTML和CSS创建一个响应式卡片布局,要求:
1. 使用Flex布局和移动优先策略
2. 手机(<768px):单列布局
3. 平板(768-1024px):两列布局
4. 电脑(>1024px):三列布局
5. 卡片有阴影、圆角、悬停效果
6. 代码注释清晰,使用语义化HTML标签
优点:具体、清晰、有要求


5.4.2 迭代优化:一步步完善

第一版Prompt:生成基础布局

1
创建一个响应式卡片布局

第二版Prompt:添加样式要求

1
2
3
4
在刚才的基础上,添加:
- 卡片阴影效果
- 悬停动画
- 现代化配色

第三版Prompt:优化细节

1
调整间距和字体大小,让布局更协调

💡 技巧
不要一次要求太多,分步骤让AI生成,更容易得到好结果。


5.4.3 检查AI生成的代码

必须检查的点: - ✅ 是否添加了viewport元标签? - ✅ 媒体查询语法是否正确? - ✅ 断点值是否合理? - ✅ 代码是否符合移动优先策略? - ✅ 是否有明显的bug?

测试方法: 1. 在浏览器中打开 2. 用F12开发者工具测试不同设备 3. 检查是否有布局问题


5.5 常见问题与解决方案

问题1:AI生成的代码不工作?

可能原因: - 缺少viewport元标签 - CSS文件路径错误 - 语法错误

解决方案

1
2
<!-- 确保有这行 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

1
2
<!-- 检查CSS文件路径 -->
<link rel="stylesheet" href="style.css">

问题2:AI生成的代码不符合需求?

解决方案: 1. 更详细地描述需求(写更具体的Prompt) 2. 分步骤生成(先基础布局,再添加样式) 3. 手动调整(AI生成的是起点,不是终点)


问题3:如何让AI生成更好的代码?

技巧: - ✅ 明确指定技术栈(Flex布局、媒体查询) - ✅ 说明设计风格(现代化、简洁) - ✅ 要求代码注释 - ✅ 指定断点值 - ✅ 要求移动优先策略


5.6 本节总结

你已经学会了:

AI生成响应式布局的方法: - 如何设计有效的Prompt - 如何迭代优化代码 - 如何检查生成的代码

实战技能: - 用AI生成响应式导航栏 - 用AI生成响应式卡片布局 - 优化AI生成的代码

最佳实践: - 分步骤生成代码 - 详细描述需求 - 测试和优化

🌟 记住
AI是强大的工具,但不能替代你的思考
- AI生成代码 → 你测试和优化 → 最终产品
- 理解代码原理 → 才能用好AI工具
- 多练习 → 才能写出更好的Prompt

AI + 你的思考 = 高效开发!


6. 选讲:CSS变量与主题定制

6.1 为什么需要CSS变量?

6.1.1 传统方式的痛点

生活场景
想象你在装修房子,选了一个主色调"蓝色": - 客厅用蓝色 - 卧室用蓝色 - 厨房用蓝色

问题来了:如果有一天你想改成"绿色",怎么办? - ❌ 传统方式:找到所有用蓝色的地方,一个一个改成绿色(100个地方要改100次!) - ✅ CSS变量方式:改一个变量的值,所有地方自动变成绿色(改1次,全部生效!)

传统CSS的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 传统方式:每个地方都要写具体的颜色值 */
.header {
background-color: #3498db; /* 蓝色 */
}

.button {
background-color: #3498db; /* 又是蓝色 */
}

.link {
color: #3498db; /* 还是蓝色 */
}

/* 想改成绿色?要改3个地方! */

💡 核心问题
同样的颜色值(如#3498db)在代码中重复出现很多次,修改时需要在多个地方改,容易出错,维护困难。


6.1.2 CSS变量的诞生(2015年)

2015年,CSS3正式引入CSS变量(CSS Custom Properties),让样式管理变得简单:

传统方式 CSS变量方式
重复写相同的值 定义一次,到处使用
修改要改很多地方 修改只需改1个地方
容易出错 不容易出错
代码冗长 代码简洁

🌟 历史意义
CSS变量让样式管理从"手工作坊"变成了"现代化工厂",是CSS发展史上的重要进步。


6.2 什么是CSS变量?

6.2.1 生活类比

CSS变量就像"调色板": - 定义一次颜色(如"主色调 = 蓝色") - 在需要的地方引用("用主色调") - 想换颜色?改调色板上的定义就行

CSS变量: - 定义一次值(如--main-color: #3498db;) - 在需要的地方引用(color: var(--main-color);) - 想换颜色?改变量的定义就行


6.2.2 CSS变量的定义

CSS变量 = 可以重复使用的CSS值

基本语法

1
2
3
4
5
6
7
8
9
/* 定义变量 */
:root {
--变量名: 值;
}

/* 使用变量 */
选择器 {
属性: var(--变量名);
}

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 定义变量 */
:root {
--main-color: #3498db; /* 主色调:蓝色 */
--font-size: 16px; /* 字体大小 */
}

/* 使用变量 */
.header {
background-color: var(--main-color); /* 使用主色调 */
}

.button {
background-color: var(--main-color); /* 使用主色调 */
}

.text {
font-size: var(--font-size); /* 使用字体大小 */
}

效果: - .header.button都使用蓝色背景 - .text使用16px字体大小 - 想改颜色?改--main-color的值就行!


6.3 CSS变量的语法详解

6.3.1 定义变量

语法--变量名: 值;

规则: - 变量名必须以--开头(两个短横线) - 变量名区分大小写(--color--Color是不同的变量) - 值可以是任何CSS值(颜色、尺寸、字符串等)

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
:root {
/* 颜色变量 */
--primary-color: #3498db;
--secondary-color: #2ecc71;

/* 尺寸变量 */
--spacing: 20px;
--font-size-large: 24px;

/* 字符串变量 */
--font-family: '微软雅黑', Arial, sans-serif;
}

💡 命名建议
使用有意义的变量名,如--main-color而不是--color1,这样代码更容易理解。


6.3.2 使用变量

语法var(--变量名)

实际例子

1
2
3
4
5
.button {
background-color: var(--primary-color); /* 使用主色调 */
padding: var(--spacing); /* 使用间距 */
font-size: var(--font-size-large); /* 使用大字体 */
}

效果.button的背景色、内边距、字体大小都使用变量中定义的值。


6.3.3 变量的作用域

生活类比
变量的作用域就像"房间的规则": - 全局变量:root)= 整个房子的规则(所有房间都遵守) - 局部变量(特定元素)= 某个房间的规则(只有这个房间遵守)

CSS变量的作用域

定义位置 作用域 示例
:root 全局(整个文档) 所有元素都能使用
特定元素 局部(该元素及其子元素) 只有该元素内部能使用

实际例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 全局变量:所有元素都能用 */
:root {
--main-color: #3498db;
}

/* 局部变量:只有.container内部能用 */
.container {
--local-color: #e74c3c;
}

/* 使用全局变量 */
.header {
color: var(--main-color); /* ✅ 可以用 */
}

/* 使用局部变量 */
.container .item {
color: var(--local-color); /* ✅ 可以用(在.container内部) */
}

.other {
color: var(--local-color); /* ❌ 不能用(不在.container内部) */
}


6.3.4 变量的默认值

语法var(--变量名, 默认值)

作用:如果变量未定义,使用默认值

实际例子

1
2
3
.text {
color: var(--text-color, #333); /* 如果--text-color未定义,使用#333 */
}

💡 使用场景
当不确定变量是否已定义时,使用默认值可以避免样式失效。


6.4 实战案例:使用CSS变量实现主题切换

6.4.1 需求分析

我们要实现一个主题切换功能: - 默认:明亮模式(白色背景、黑色文字) - 切换后:暗黑模式(深色背景、浅色文字) - 点击按钮切换主题


6.4.2 HTML结构

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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主题切换示例</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>我的网站</h1>
<button id="theme-toggle">🌙 切换到暗黑模式</button>
</header>

<main>
<div class="card">
<h2>卡片标题</h2>
<p>这是卡片的内容。点击右上角的按钮可以切换主题。</p>
</div>

<div class="card">
<h2>另一个卡片</h2>
<p>暗黑模式对眼睛更友好,特别是在晚上使用。</p>
</div>
</main>
</div>

<script src="script.js"></script>
</body>
</html>

6.4.3 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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* ===== 定义CSS变量(明亮模式,默认) ===== */
:root {
--bg-color: #ffffff; /* 背景色:白色 */
--text-color: #333333; /* 文字颜色:深灰色 */
--card-bg: #f5f5f5; /* 卡片背景:浅灰色 */
--border-color: #e0e0e0; /* 边框颜色:浅灰色 */
--button-bg: #3498db; /* 按钮背景:蓝色 */
--button-text: #ffffff; /* 按钮文字:白色 */
}

/* ===== 暗黑模式变量 ===== */
[data-theme="dark"] {
--bg-color: #1a1a1a; /* 背景色:深色 */
--text-color: #f0f0f0; /* 文字颜色:浅色 */
--card-bg: #2d2d2d; /* 卡片背景:深灰色 */
--border-color: #404040; /* 边框颜色:灰色 */
--button-bg: #4a9eff; /* 按钮背景:亮蓝色 */
--button-text: #ffffff; /* 按钮文字:白色 */
}

/* ===== 应用变量到样式 ===== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
background-color: var(--bg-color); /* 使用背景色变量 */
color: var(--text-color); /* 使用文字颜色变量 */
font-family: '微软雅黑', Arial, sans-serif;
transition: background-color 0.3s, color 0.3s; /* 平滑过渡 */
min-height: 100vh;
}

.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid var(--border-color); /* 使用边框颜色变量 */
}

h1 {
font-size: 32px;
}

#theme-toggle {
background-color: var(--button-bg); /* 使用按钮背景变量 */
color: var(--button-text); /* 使用按钮文字变量 */
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}

#theme-toggle:hover {
opacity: 0.9;
}

main {
display: flex;
flex-direction: column;
gap: 20px;
}

.card {
background-color: var(--card-bg); /* 使用卡片背景变量 */
padding: 20px;
border-radius: 8px;
border: 1px solid var(--border-color); /* 使用边框颜色变量 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s, border-color 0.3s;
}

.card h2 {
margin-bottom: 10px;
color: var(--text-color); /* 使用文字颜色变量 */
}

.card p {
line-height: 1.6;
color: var(--text-color); /* 使用文字颜色变量 */
}

6.4.4 JavaScript代码(实现主题切换)

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
// 获取切换按钮
const themeToggle = document.getElementById('theme-toggle');

// 检查本地存储中是否有保存的主题
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
updateButtonText(savedTheme);

// 点击按钮切换主题
themeToggle.addEventListener('click', function() {
// 获取当前主题
const currentTheme = document.documentElement.getAttribute('data-theme');

// 切换主题
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);

// 保存到本地存储(下次打开页面时记住用户的选择)
localStorage.setItem('theme', newTheme);

// 更新按钮文字
updateButtonText(newTheme);
});

// 更新按钮文字
function updateButtonText(theme) {
if (theme === 'dark') {
themeToggle.textContent = '☀️ 切换到明亮模式';
} else {
themeToggle.textContent = '🌙 切换到暗黑模式';
}
}

6.4.5 代码解析(逐步理解)

第一步:定义变量(明亮模式)

1
2
3
4
:root {
--bg-color: #ffffff; /* 白色背景 */
--text-color: #333333; /* 深色文字 */
}

效果:定义默认主题的变量。

第二步:定义变量(暗黑模式)

1
2
3
4
[data-theme="dark"] {
--bg-color: #1a1a1a; /* 深色背景 */
--text-color: #f0f0f0; /* 浅色文字 */
}

效果:当<html>元素有data-theme="dark"属性时,使用暗黑模式的变量值。

第三步:应用变量

1
2
3
4
body {
background-color: var(--bg-color); /* 使用变量 */
color: var(--text-color); /* 使用变量 */
}

效果body的背景色和文字颜色会根据当前主题自动变化。

第四步:JavaScript切换主题

1
document.documentElement.setAttribute('data-theme', 'dark');

效果:给<html>元素添加data-theme="dark"属性,触发暗黑模式的CSS变量。


6.4.6 最终效果

明亮模式: - 白色背景 - 深色文字 - 浅色卡片

暗黑模式: - 深色背景 - 浅色文字 - 深色卡片

切换效果: - 点击按钮 → 主题立即切换 - 切换有平滑过渡动画 - 用户选择会保存到本地存储(下次打开页面时记住)


6.5 更多实战案例

案例1:多主题切换(不只是明亮/暗黑)

需求:支持明亮、暗黑、蓝色主题三种模式

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 明亮主题(默认) */
:root {
--bg-color: #ffffff;
--text-color: #333333;
--primary-color: #3498db;
}

/* 暗黑主题 */
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #f0f0f0;
--primary-color: #4a9eff;
}

/* 蓝色主题 */
[data-theme="blue"] {
--bg-color: #e3f2fd;
--text-color: #1565c0;
--primary-color: #1976d2;
}

JavaScript

1
2
3
4
5
6
7
const themes = ['light', 'dark', 'blue'];
let currentIndex = 0;

themeToggle.addEventListener('click', function() {
currentIndex = (currentIndex + 1) % themes.length;
document.documentElement.setAttribute('data-theme', themes[currentIndex]);
});


案例2:响应式变量(根据屏幕大小改变值)

需求:不同屏幕大小使用不同的间距

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
:root {
--spacing: 10px; /* 默认间距 */
}

/* 平板:增大间距 */
@media (min-width: 768px) {
:root {
--spacing: 20px;
}
}

/* 电脑:更大间距 */
@media (min-width: 1024px) {
:root {
--spacing: 30px;
}
}

.container {
padding: var(--spacing); /* 自动适应不同屏幕 */
}


6.6 CSS变量的优势总结

优势 说明 实际效果
代码复用 定义一次,到处使用 减少重复代码
易于维护 修改只需改1个地方 改颜色只需改变量定义
动态切换 通过JavaScript动态改变 实现主题切换功能
作用域控制 全局或局部变量 灵活控制应用范围
类型安全 值可以是任何CSS类型 支持颜色、尺寸、字符串等

6.7 常见问题与解决方案

问题1:CSS变量不生效?

可能原因: 1. 变量名写错了(必须是--开头) 2. 作用域问题(变量定义的位置不对) 3. 浏览器不支持(IE不支持CSS变量)

解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 1. 检查变量名 */
:root {
--main-color: #3498db; /* ✅ 正确:--开头 */
main-color: #3498db; /* ❌ 错误:没有-- */
}

/* 2. 检查作用域 */
:root {
--color: #3498db; /* ✅ 全局变量,所有地方都能用 */
}

.container {
--color: #e74c3c; /* ✅ 局部变量,只有.container内部能用 */
}

/* 3. 提供回退值 */
.text {
color: var(--text-color, #333); /* 如果变量未定义,使用#333 */
}


问题2:如何在不支持CSS变量的浏览器中使用?

解决方案

1
2
3
4
5
/* 提供回退值 */
.button {
background-color: #3498db; /* 回退值(不支持CSS变量的浏览器用这个) */
background-color: var(--primary-color, #3498db); /* CSS变量(支持的浏览器用这个) */
}

💡 注意
现代浏览器(Chrome、Firefox、Safari、Edge)都支持CSS变量。
只有IE浏览器不支持,但IE已经停止更新,可以忽略。


问题3:变量名应该怎么命名?

推荐命名方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* ✅ 好的命名:语义化、清晰 */
:root {
--primary-color: #3498db; /* 主色调 */
--secondary-color: #2ecc71; /* 次要颜色 */
--spacing-small: 10px; /* 小间距 */
--spacing-large: 30px; /* 大间距 */
}

/* ❌ 不好的命名:不清晰 */
:root {
--color1: #3498db;
--color2: #2ecc71;
--size1: 10px;
--size2: 30px;
}


6.8 本节总结

你已经学会了:

CSS变量的核心概念: - 什么是CSS变量 - 为什么需要CSS变量 - 变量的作用域

CSS变量的语法: - 如何定义变量(:root、局部变量) - 如何使用变量(var()函数) - 变量的默认值

实战技能: - 使用CSS变量实现主题切换 - 多主题切换 - 响应式变量

最佳实践: - 变量命名规范 - 浏览器兼容性处理 - 代码组织方式

🌟 记住
CSS变量是现代Web开发的重要工具
掌握了CSS变量,你就能: - 让代码更简洁、易维护 - 实现动态主题切换 - 提升开发效率

CSS变量 + JavaScript = 强大的主题定制能力!


本章总结

通过本章的学习,你已经掌握了:

CSS基础: - CSS的作用和重要性 - CSS选择器的使用 - 选择器优先级

Flex布局: - Flex容器和Flex项目 - 主轴和交叉轴 - 常用属性(justify-contentalign-items等) - 实现导航栏布局

响应式设计: - 媒体查询的语法和应用 - 断点的概念 - 移动优先策略 - 制作自适应页面

AI辅助开发: - 用AI生成响应式布局 - 优化AI生成的代码 - 写出更好的Prompt

CSS变量(选讲): - CSS变量的定义和使用 - 实现主题切换功能

🌟 恭喜你!
你已经掌握了现代Web开发中CSS的核心技能!
这些知识将帮助你: - 制作美观的网页界面 - 实现响应式布局 - 提升开发效率

继续练习,继续探索,Web开发的世界等着你! 🚀