03 — CSS 基础回顾

你说你有 CSS 基础。本章不重复教 CSS,而是把项目里用到的、可能你没接触过的语法挑出来讲。
大约 10 分钟读完。


1. CSS 变量(自定义属性)— 项目核心

这是最重要的概念,项目所有颜色/间距/字体都用 CSS 变量统一管理。

1.1 定义与使用

1
2
3
4
5
6
7
/* src/styles/tokens.css */
:root {
--color-primary: #e8a548; /* 定义变量 */
--bg-surface: #141311;
--space-4: 16px;
--radius-md: 10px;
}
1
2
3
4
5
6
/* 任何文件里都能用 */
.button {
background: var(--color-primary);
padding: var(--space-4);
border-radius: var(--radius-md);
}

1.2 为什么要用变量?

1
2
3
4
5
6
7
8
9
10
/* ❌ 不用变量:改主色要改 100 个地方 */
.a { color: #e8a548; }
.b { border-color: #e8a548; }
.c { background: #e8a548; }

/* ✅ 用变量:只改一处 */
:root { --color-primary: #e8a548; }
.a { color: var(--color-primary); }
.b { border-color: var(--color-primary); }
.c { background: var(--color-primary); }

1.3 变量可以是颜色、字符串、甚至一整段样式

1
2
3
4
5
6
:root {
--color-primary: #e8a548;
--bg-gradient: radial-gradient(ellipse at top, #1a1510 0%, #0c0b09 100%);
--accent-line: linear-gradient(90deg, transparent, var(--color-primary), transparent);
--shadow-glow: 0 0 20px rgba(232, 165, 72, 0.15); /* 注意:完整的 shadow 值 */
}

使用:

1
2
3
4
.top {
background: var(--accent-line); /* 直接用整个 gradient */
box-shadow: var(--shadow-glow);
}

1.4 变量里再引用变量

1
2
3
4
5
:root {
--color-primary: #e8a548;
--accent-line: linear-gradient(90deg, transparent, var(--color-primary), transparent);
/* ↑ 在变量定义里引用别的变量 ✓ */
}

2. CSS Modules — *.module.css

文件命名规则:任何文件名包含 .module.css 的 CSS 文件,Vite 会把它当作 CSS Module 处理。

2.1 核心规则:类名会被「哈希」成唯一的

1
2
3
4
5
6
7
8
/* ChatItem.module.css */
.item {
padding: 12px;
}

.active {
background: gold;
}
1
2
3
import styles from './ChatItem.module.css';
// styles.item = "ChatItem_item_a1b2c3"
// styles.active = "ChatItem_active_x7y8z9"

编译后的 HTML

1
<div class="ChatItem_item_a1b2c3 ChatItem_active_x7y8z9">

好处:不同组件的 .item 不会冲突。即使 Sidebar.module.css 里也有 .item,也完全是不同的类名。

2.2 项目里到处可见的模式

1
2
3
4
5
6
7
8
// 字符串拼接条件类名
<div className={`${styles.item} ${active ? styles.active : ''}`}>

// 多个条件
<button
className={`${styles.sendBtn} ${isSending ? styles.stop : ''} ${!canSend ? styles.disabled : ''}`}
disabled={isSending ? false : !canSend}
>

2.3 :global() — 让类名不被哈希

如果想在 CSS Module 里写「全局类名」(不被哈希):

1
2
3
4
/* Markdown.module.css - 覆盖 highlight.js 的样式 */
.markdown :global(.hljs) {
background: transparent;
}

:global() 里的 .hljs 保持原样,不被哈希。
这在覆盖第三方库样式时特别有用。

2.4 嵌套选择器

CSS Module 支持嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Sidebar.module.css */
.item {
padding: 12px;
}

.item:hover { /* 等价于 .item:hover */
background: #201e1b;
}

.item.active { /* 等价于 .item.active */
color: white;
}

.item .deleteBtn { /* 等价于 .item .deleteBtn */
opacity: 0;
}

.item:hover .deleteBtn { /* 等价于 .item:hover .deleteBtn */
opacity: 1;
}

3. 单位与数值

3.1 rem vs px vs em

1
2
3
font-size: 14px;             /* 像素:绝对单位 */
font-size: 1rem; /* 相对根元素 (html) 的字号 */
font-size: 1em; /* 相对父元素的字号 */

项目里用 px 居多,rem 也有。本地不用太纠结,看到 1.5rem 就当作”稍大一号”。

3.2 颜色值多种写法

1
2
3
4
5
color: #e8a548;             /* 16进制 */
color: #e8a5; /* 16进制带透明度(最后两位) */
color: rgb(232, 165, 72); /* RGB */
color: rgba(232, 165, 72, 0.5); /* RGBA 带透明度 */
color: transparent; /* 透明 */

3.3 calc() 计算

1
2
/* 项目里没怎么用,但要知道 */
width: calc(100% - 16px);

4. Flexbox(重点)

项目大量使用 flexbox。这是必备技能。

4.1 基本用法

1
2
3
4
5
.container {
display: flex; /* 子元素横向排列 */
gap: 12px; /* 子元素间距(推荐用 gap 而不是 margin) */
padding: 16px;
}

4.2 项目里的常见 flex 模式

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
/* 居中(垂直 + 水平) */
.center {
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
}

/* 一行内 头像 + 内容 */
.row {
display: flex;
gap: 12px;
align-items: flex-start; /* 顶部对齐 */
}
.avatar { width: 32px; height: 32px; }
.content { flex: 1; } /* 占满剩余空间 */

/* 垂直堆叠 */
.column {
display: flex;
flex-direction: column;
gap: 8px;
}

/* 两端对齐(左侧标题,右侧按钮) */
.space-between {
display: flex;
justify-content: space-between;
align-items: center;
}

4.3 项目里 Sidebar.tsx + Sidebar.module.css 的实际例子

1
2
3
4
5
6
7
8
9
// Sidebar.module.css
.list {
flex: 1; /* 占据剩余高度 */
overflow-y: auto; /* 内容多就滚动 */
padding: 8px;
display: flex;
flex-direction: column; /* 垂直排列每个 ChatItem */
gap: 4px;
}

理解

  • 父级 sidebar 是 display: flex; flex-direction: column
  • 子级:header / list / footer
  • list 用 flex: 1 占据中间所有可用高度
  • list 内部再 display: flex; flex-direction: column 让 ChatItem 垂直堆叠

5. 媒体查询(响应式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 默认:桌面 */
.sidebar {
width: 280px;
}

/* 小于 768px 时:变成移动端抽屉 */
@media (max-width: 767px) {
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 60;
transform: translateX(-100%); /* 默认隐藏在屏幕外 */
}

.sidebar.drawerOpen {
transform: translateX(0); /* 打开时滑入屏幕 */
}
}

@media 里写的样式只在满足条件时生效。本项目用 max-width: 767px 判断移动端。


6. 动画与过渡

6.1 transition — 过渡动画

1
2
3
4
5
6
7
8
9
.button {
background: gold;
transition: all 250ms ease; /* 所有属性变化时,250ms 缓动 */
}

.button:hover {
background: orange;
transform: scale(1.05); /* 悬停时放大 */
}

transition 的语法transition: 属性名 时长 缓动函数

1
2
transition: background 200ms ease;            /* 只过渡 background */
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1); /* 全部,自定义曲线 */

6.2 @keyframes + animation — 关键帧动画

1
2
3
4
5
6
7
8
9
10
/* 定义 */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}

/* 使用 */
.message {
animation: fadeIn 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

项目里用到的动画:

名字效果用途
fadeIn淡入 + 上移消息/对话框入场
slideUp滑入 + 缩放确认弹窗
bounce弹跳AI 思考中的三点
pulse呼吸灯工具调用进行中
spin旋转加载图标

6.3 transform 常用值

1
2
3
4
transform: translateX(8px);     /* 水平位移 */
transform: translateY(-2px); /* 垂直位移(负数 = 向上) */
transform: scale(1.05); /* 缩放 */
transform: rotate(360deg); /* 旋转 */

7. 一些常用 CSS 属性速查

7.1 边框与轮廓

1
2
3
border: 1px solid rgba(255, 248, 240, 0.08);
border-radius: 10px; /* 圆角 */
outline: none; /* 去除聚焦时的蓝框 */

7.2 阴影

1
2
3
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
/* ↑ x偏移 y偏移 模糊半径 颜色 */
box-shadow: 0 0 20px rgba(232, 165, 72, 0.15); /* 0偏移 = 发光效果 */

7.3 定位与层级

1
2
3
4
position: relative;             /* 相对定位(占原位) */
position: absolute; /* 绝对定位(相对最近的 positioned 父元素) */
position: fixed; /* 固定定位(相对视口) */
z-index: 100; /* 层级,越大越靠上 */

7.4 截断与省略号

1
2
3
4
5
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* 单行省略号 */
}

8. 本项目 CSS 系统的特点

特点说明
CSS 变量集中管理tokens.css 一处定义,全局使用
CSS Modules每个组件样式独立,类名自动哈希
Flex 布局为主不使用 Grid、不使用 float
CSS 自定义动画没用动画库,纯 CSS keyframes
响应式最小化仅 sidebar 有 @media,主内容自适应
❌ 不用 Sass/Less纯 CSS
❌ 不用 Tailwind用 CSS Module + CSS 变量

接下来

现在你应该能读懂项目里大部分 CSS 了。
继续阅读 04-JavaScript基础回顾.md,了解 JavaScript 那些你可能不熟的语法。