Appearance
CSS
CSS 不是“写点样式”这么简单。
更具体一点,CSS 负责的是:
- 页面视觉样式的表达
- 元素空间布局的组织
- 不同状态下的界面反馈
- 在不同屏幕和设备上的适配表现
如果 HTML 决定“页面是什么”,JavaScript 决定“页面怎么交互”,那 CSS 决定的就是:
页面最终看起来是什么样,以及它为什么会这样排布。
1. CSS 在解决什么问题
CSS 的核心作用可以概括成三层:
- 控制视觉样式,比如颜色、字号、间距、边框
- 控制空间布局,比如元素如何排列、对齐、伸缩和换行
- 控制状态表达,比如
hover、focus、过渡和动画
很多人在初学阶段会把 CSS 理解成“调样式的语法集合”,但工程里更重要的是:你是否理解一个元素为什么出现在那个位置,为什么它会覆盖别人,为什么在不同屏幕下表现不同。
2. 一条更适合理解 CSS 的主线
系统学习 CSS 时,通常更适合按下面顺序来理解:
- 先理解选择器、继承、层叠、优先级这些“规则怎么生效”
- 再理解盒模型、文档流、定位这些“元素怎么排布”
- 再进入
Flex、Grid、响应式这些现代布局能力 - 最后再补动画、过渡和工程化组织方式
如果顺序反过来,往往会出现:
- 会写
flex: 1,但不知道为什么宽度不对 - 会写
position: absolute,但不知道它到底相对谁定位 - 会写媒体查询,但不知道页面为什么还是会错位
3. 样式到底是怎么应用到元素上的
浏览器拿到 HTML 和 CSS 后,并不是“看一眼就知道该怎么渲染”,它要先完成样式匹配和计算。
看一条非常简化的主线:
mermaid
flowchart TD
A[浏览器拿到 HTML 和 CSS] --> B[根据选择器匹配元素]
B --> C[结合继承和层叠计算最终样式]
C --> D[生成盒模型和布局信息]
D --> E[完成绘制与展示]最值得先记住的是:CSS 不是单条规则直接生效,而是很多规则共同参与后,才得到元素最终样式。
4. 选择器到底在做什么
选择器的本质,是告诉浏览器:这条样式规则要作用到哪些元素上。
常见选择器包括:
- 标签选择器,例如
div - 类选择器,例如
.card - ID 选择器,例如
#app - 后代选择器,例如
.article p - 子选择器,例如
.list > li - 伪类,例如
:hover、:focus - 伪元素,例如
::before、::after
例如:
css
article p {
color: #333;
}
.button:hover {
background-color: #1677ff;
}4.1 选择器不是越复杂越好
很多人写 CSS 时容易把选择器层级堆得很深,例如:
css
.page .content .article .card .title {
color: #111;
}这类写法的问题在于:
- 耦合页面结构
- 复用性差
- 后续维护时更容易引发覆盖问题
工程上更常见的做法是:尽量让类名本身表达组件语义,而不是过度依赖很深的结构选择器。
5. 继承、层叠、优先级分别是什么意思
这三个词很容易一起出现,但职责并不一样。
5.1 继承
继承可以看成 某些样式属性会从父元素自然传给子元素。
比如文本颜色、字体族,往往就有继承性。
但像 margin、border、width 这类布局相关属性,通常不会自动继承。
5.2 层叠
层叠说的是:当多条规则同时命中一个元素时,浏览器如何决定最终采用哪条。
也就是说,CSS 不是“命中即生效”,而是“命中后还要比较”。
5.3 优先级
优先级可以看成 不同选择器之间,谁的话更有分量。
通常可以记住一个大致顺序:
- 行内样式优先级很高
- ID 选择器高于类、属性、伪类
- 类、属性、伪类高于标签、伪元素
5.4 !important 为什么不适合滥用
!important 会强行提升规则权重。
它不是绝对不能用,但如果大量使用,通常说明:
- 选择器体系已经变乱
- 样式覆盖关系不清楚
- 后续维护成本会越来越高
6. 盒模型为什么是 CSS 的基础
浏览器不会把元素当成“抽象标签”,而是把它们当成一个个盒子来计算大小和位置。
一个盒子通常包含:
contentpaddingbordermargin
看一张简化图:
mermaid
flowchart TD
A[margin 外边距] --> B[border 边框]
B --> C[padding 内边距]
C --> D[content 内容区]如果把它换成更贴近“最终占位空间”的理解,可以再看一眼这条主线:
mermaid
flowchart TD
A[元素最终占位空间] --> B[margin 决定和外界的距离]
B --> C[border 决定边框范围]
C --> D[padding 决定内容和边框的内侧留白]
D --> E[content 真正承载文字和图片]6.1 box-sizing 为什么经常被统一设置
默认情况下,width 和 height 通常只描述内容区大小。
这意味着:
- 你写了
width: 200px - 再加上
padding和border - 元素最终占据空间会比
200px更大
所以现代项目里经常会统一设置:
css
*,
*::before,
*::after {
box-sizing: border-box;
}它的作用是:让 width 和 height 更接近我们直觉里“这个盒子最终有多大”的理解。
7. 文档流到底是什么
文档流可以看成 浏览器在默认情况下安排元素顺序和位置的一套基础规则。
例如:
- 块级元素通常从上到下排列
- 行内内容通常从左到右排布
- 后出现的元素通常排在前一个元素后面
很多布局问题,本质上不是“Flex 没写对”,而是:你没有看清这个元素当前是否还在正常文档流里。
看一张“正常文档流”的直观图:
mermaid
flowchart TD
A[正常文档流] --> B[块级元素通常从上到下排列]
A --> C[行内内容通常从左到右排列]
A --> D[后出现的元素通常排在前一个元素后面]8. display 到底在控制什么
display 很重要,因为它会直接影响元素参与布局的方式。
最常见的几种值包括:
blockinlineinline-blocknoneflexgrid
这些值不是简单的“显示样式切换”,而是在决定:
- 元素是否独占一行
- 是否能设置宽高
- 子元素会用哪种布局模型排布
9. 定位为什么总是容易让人混乱
position 这条主线很重要,因为它会影响元素是否脱离正常文档流、相对谁定位、以及层级关系。
常见值包括:
staticrelativeabsolutefixedsticky
9.1 它们分别可以怎么理解
static:默认状态,元素按正常文档流排布relative:元素还在原位置附近,但可以相对自己原本位置偏移absolute:脱离正常文档流,相对最近的定位祖先元素定位fixed:相对视口固定sticky:在特定滚动条件下表现为“吸附”
可以再配合下面这张图看:
mermaid
flowchart TD
A[position]
A --> B[static 仍在正常文档流]
A --> C[relative 仍在正常文档流 但可以偏移]
A --> D[absolute 脱离正常文档流 相对定位祖先]
A --> E[fixed 脱离正常文档流 相对视口]
A --> F[sticky 在滚动阈值前后切换表现]9.2 为什么 absolute 经常让人误解
很多人会把 absolute 理解成“绝对地相对整个页面定位”,这并不准确。
更具体一点:absolute 会优先相对最近的非 static 定位祖先元素定位。`
如果没有这样的祖先,它才更接近相对初始包含块定位。
10. 层叠上下文和 z-index 到底怎么回事
很多人遇到遮挡问题时,第一反应是不断加大 z-index。
但真正的问题往往不是“数字不够大”,而是:元素是否处在同一个层叠上下文里。
可以这样理解:
z-index不是全局统一比较- 不同层叠上下文之间,各自内部先比较,再整体参与外层排序
这也是为什么有时候你把一个元素写成 z-index: 9999,它仍然可能被别的区域挡住。
11. Flex 为什么会成为现代布局基础
Flex 更适合一维布局,也就是:在一条主轴上安排元素的顺序、对齐、伸缩和换行。
它非常适合:
- 水平排列按钮
- 垂直居中内容
- 做自适应列表
- 做头部、卡片、导航等常见结构
例如:
css
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}11.1 Flex 最值得先掌握什么
抓住这几个点通常最有用:
- 主轴和交叉轴
justify-contentalign-itemsgapflex-grow、flex-shrink、flex-basis
要注意的是:Flex 很强,但它并不是所有布局问题的通用答案。
可以把 Flex 理解成这样一张图:
mermaid
flowchart LR
A[Flex 容器] --> B[主轴方向排列]
A --> C[交叉轴方向对齐]
B --> D[子项可以伸缩]
B --> E[子项可以换行]12. Grid 为什么适合更复杂的二维布局
如果说 Flex 更擅长一维排列,那 Grid 更适合 同时控制行和列的二维布局。
它非常适合:
- 仪表盘
- 复杂卡片矩阵
- 页面主体分区
- 后台管理布局
例如:
css
.dashboard {
display: grid;
grid-template-columns: 240px 1fr;
gap: 16px;
}12.1 Flex 和 Grid 怎么选
可以按这个经验判断:
- 一维排列优先考虑
Flex - 二维网格优先考虑
Grid
也就是说,不要把它们理解成互斥关系,而应该理解成:它们分别更擅长不同类型的布局问题。
可以再看一张 Flex 和 Grid 的对照图:
mermaid
flowchart LR
A[布局问题] --> B[Flex 一维布局]
A --> C[Grid 二维布局]
B --> D[更适合单行或单列的排列与对齐]
C --> E[更适合同时控制行和列]13. 响应式设计到底在解决什么问题
响应式不是“页面缩一缩就行”,而是在解决:同一份内容,如何在不同屏幕尺寸和设备环境下保持可读、可用和稳定。
最常见的手段包括:
- 弹性布局
- 百分比和相对单位
- 媒体查询
- 图片和容器自适应
例如:
css
.container {
width: min(100% - 32px, 1200px);
margin: 0 auto;
}
@media (max-width: 768px) {
.sidebar {
display: none;
}
}13.1 常见单位怎么选
常见单位包括:
px%emremvwvh
它们分别更适合不同问题:
px适合明确尺寸%适合相对父容器比例rem更适合和根字体联动的统一缩放vw、vh更适合和视口尺寸直接关联
14. 动画和过渡应该怎么理解
这部分不是“做点花哨效果”,而是在表达:状态变化时,界面如何更自然地从一种状态过渡到另一种状态。
最常见的两种方式是:
transitionanimation
14.1 transition
更适合简单状态切换,例如:
css
.button {
transition: background-color 0.2s ease, transform 0.2s ease;
}
.button:hover {
background-color: #1677ff;
transform: translateY(-2px);
}14.2 animation
更适合更完整的关键帧动画。
css
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.panel {
animation: fade-in 0.3s ease;
}15. CSS 工程里最容易踩的坑
15.1 选择器层级写得过深
这会让样式和结构强耦合,后面一改 DOM 就容易失效。
15.2 不理解文档流就强上定位
很多定位问题,本质上是默认布局没看懂。
15.3 遇到覆盖问题就堆 !important
这通常会让样式系统越来越难维护。
15.4 只会用一种布局方式
比如所有问题都想用 absolute 或所有问题都想用 flex,最后往往会把布局写得很别扭。
15.5 不考虑响应式
桌面端能看,不代表移动端也能用。
16. 一份更实用的 CSS 检查清单
写一个页面时,至少可以自查下面这些问题:
- 这条样式是否真的命中了目标元素
- 是否被更高优先级规则覆盖了
- 元素当前是否还在正常文档流中
- 盒模型大小是否符合预期
- 用
Flex还是Grid是否合理 - 是否考虑了不同屏幕尺寸下的表现
- 动画和过渡是否真的在帮助理解,而不是制造干扰
17. 小结
如果把 CSS 压缩成一句话,可以记住:CSS 负责定义页面的视觉样式、空间布局和状态变化,是把 HTML 骨架真正变成界面的关键一层。
如果继续往下读,最自然的下一步是进入 JavaScript,因为页面有了结构和样式之后,接下来就该看它如何响应用户交互和执行业务逻辑。