Skip to content

CSS

CSS 不是“写点样式”这么简单。

更具体一点,CSS 负责的是:

  1. 页面视觉样式的表达
  2. 元素空间布局的组织
  3. 不同状态下的界面反馈
  4. 在不同屏幕和设备上的适配表现

如果 HTML 决定“页面是什么”,JavaScript 决定“页面怎么交互”,那 CSS 决定的就是:

页面最终看起来是什么样,以及它为什么会这样排布。

1. CSS 在解决什么问题

CSS 的核心作用可以概括成三层:

  1. 控制视觉样式,比如颜色、字号、间距、边框
  2. 控制空间布局,比如元素如何排列、对齐、伸缩和换行
  3. 控制状态表达,比如 hoverfocus、过渡和动画

很多人在初学阶段会把 CSS 理解成“调样式的语法集合”,但工程里更重要的是:你是否理解一个元素为什么出现在那个位置,为什么它会覆盖别人,为什么在不同屏幕下表现不同。

2. 一条更适合理解 CSS 的主线

系统学习 CSS 时,通常更适合按下面顺序来理解:

  1. 先理解选择器、继承、层叠、优先级这些“规则怎么生效”
  2. 再理解盒模型、文档流、定位这些“元素怎么排布”
  3. 再进入 FlexGrid、响应式这些现代布局能力
  4. 最后再补动画、过渡和工程化组织方式

如果顺序反过来,往往会出现:

  1. 会写 flex: 1,但不知道为什么宽度不对
  2. 会写 position: absolute,但不知道它到底相对谁定位
  3. 会写媒体查询,但不知道页面为什么还是会错位

3. 样式到底是怎么应用到元素上的

浏览器拿到 HTML 和 CSS 后,并不是“看一眼就知道该怎么渲染”,它要先完成样式匹配和计算。

看一条非常简化的主线:

mermaid
flowchart TD
    A[浏览器拿到 HTML 和 CSS] --> B[根据选择器匹配元素]
    B --> C[结合继承和层叠计算最终样式]
    C --> D[生成盒模型和布局信息]
    D --> E[完成绘制与展示]

最值得先记住的是:CSS 不是单条规则直接生效,而是很多规则共同参与后,才得到元素最终样式。

4. 选择器到底在做什么

选择器的本质,是告诉浏览器:这条样式规则要作用到哪些元素上。

常见选择器包括:

  1. 标签选择器,例如 div
  2. 类选择器,例如 .card
  3. ID 选择器,例如 #app
  4. 后代选择器,例如 .article p
  5. 子选择器,例如 .list > li
  6. 伪类,例如 :hover:focus
  7. 伪元素,例如 ::before::after

例如:

css
article p {
  color: #333;
}

.button:hover {
  background-color: #1677ff;
}

4.1 选择器不是越复杂越好

很多人写 CSS 时容易把选择器层级堆得很深,例如:

css
.page .content .article .card .title {
  color: #111;
}

这类写法的问题在于:

  1. 耦合页面结构
  2. 复用性差
  3. 后续维护时更容易引发覆盖问题

工程上更常见的做法是:尽量让类名本身表达组件语义,而不是过度依赖很深的结构选择器。

5. 继承、层叠、优先级分别是什么意思

这三个词很容易一起出现,但职责并不一样。

5.1 继承

继承可以看成 某些样式属性会从父元素自然传给子元素

比如文本颜色、字体族,往往就有继承性。

但像 marginborderwidth 这类布局相关属性,通常不会自动继承。

5.2 层叠

层叠说的是:当多条规则同时命中一个元素时,浏览器如何决定最终采用哪条。

也就是说,CSS 不是“命中即生效”,而是“命中后还要比较”。

5.3 优先级

优先级可以看成 不同选择器之间,谁的话更有分量

通常可以记住一个大致顺序:

  1. 行内样式优先级很高
  2. ID 选择器高于类、属性、伪类
  3. 类、属性、伪类高于标签、伪元素

5.4 !important 为什么不适合滥用

!important 会强行提升规则权重。

它不是绝对不能用,但如果大量使用,通常说明:

  1. 选择器体系已经变乱
  2. 样式覆盖关系不清楚
  3. 后续维护成本会越来越高

6. 盒模型为什么是 CSS 的基础

浏览器不会把元素当成“抽象标签”,而是把它们当成一个个盒子来计算大小和位置。

一个盒子通常包含:

  1. content
  2. padding
  3. border
  4. margin

看一张简化图:

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 为什么经常被统一设置

默认情况下,widthheight 通常只描述内容区大小。

这意味着:

  1. 你写了 width: 200px
  2. 再加上 paddingborder
  3. 元素最终占据空间会比 200px 更大

所以现代项目里经常会统一设置:

css
*,
*::before,
*::after {
  box-sizing: border-box;
}

它的作用是:让 width 和 height 更接近我们直觉里“这个盒子最终有多大”的理解。

7. 文档流到底是什么

文档流可以看成 浏览器在默认情况下安排元素顺序和位置的一套基础规则

例如:

  1. 块级元素通常从上到下排列
  2. 行内内容通常从左到右排布
  3. 后出现的元素通常排在前一个元素后面

很多布局问题,本质上不是“Flex 没写对”,而是:你没有看清这个元素当前是否还在正常文档流里。

看一张“正常文档流”的直观图:

mermaid
flowchart TD
    A[正常文档流] --> B[块级元素通常从上到下排列]
    A --> C[行内内容通常从左到右排列]
    A --> D[后出现的元素通常排在前一个元素后面]

8. display 到底在控制什么

display 很重要,因为它会直接影响元素参与布局的方式。

最常见的几种值包括:

  1. block
  2. inline
  3. inline-block
  4. none
  5. flex
  6. grid

这些值不是简单的“显示样式切换”,而是在决定:

  1. 元素是否独占一行
  2. 是否能设置宽高
  3. 子元素会用哪种布局模型排布

9. 定位为什么总是容易让人混乱

position 这条主线很重要,因为它会影响元素是否脱离正常文档流、相对谁定位、以及层级关系。

常见值包括:

  1. static
  2. relative
  3. absolute
  4. fixed
  5. sticky

9.1 它们分别可以怎么理解

  1. static:默认状态,元素按正常文档流排布
  2. relative:元素还在原位置附近,但可以相对自己原本位置偏移
  3. absolute:脱离正常文档流,相对最近的定位祖先元素定位
  4. fixed:相对视口固定
  5. 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

但真正的问题往往不是“数字不够大”,而是:元素是否处在同一个层叠上下文里。

可以这样理解:

  1. z-index 不是全局统一比较
  2. 不同层叠上下文之间,各自内部先比较,再整体参与外层排序

这也是为什么有时候你把一个元素写成 z-index: 9999,它仍然可能被别的区域挡住。

11. Flex 为什么会成为现代布局基础

Flex 更适合一维布局,也就是:在一条主轴上安排元素的顺序、对齐、伸缩和换行。

它非常适合:

  1. 水平排列按钮
  2. 垂直居中内容
  3. 做自适应列表
  4. 做头部、卡片、导航等常见结构

例如:

css
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

11.1 Flex 最值得先掌握什么

抓住这几个点通常最有用:

  1. 主轴和交叉轴
  2. justify-content
  3. align-items
  4. gap
  5. flex-growflex-shrinkflex-basis

要注意的是:Flex 很强,但它并不是所有布局问题的通用答案。

可以把 Flex 理解成这样一张图:

mermaid
flowchart LR
    A[Flex 容器] --> B[主轴方向排列]
    A --> C[交叉轴方向对齐]
    B --> D[子项可以伸缩]
    B --> E[子项可以换行]

12. Grid 为什么适合更复杂的二维布局

如果说 Flex 更擅长一维排列,那 Grid 更适合 同时控制行和列的二维布局

它非常适合:

  1. 仪表盘
  2. 复杂卡片矩阵
  3. 页面主体分区
  4. 后台管理布局

例如:

css
.dashboard {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 16px;
}

12.1 Flex 和 Grid 怎么选

可以按这个经验判断:

  1. 一维排列优先考虑 Flex
  2. 二维网格优先考虑 Grid

也就是说,不要把它们理解成互斥关系,而应该理解成:它们分别更擅长不同类型的布局问题。

可以再看一张 FlexGrid 的对照图:

mermaid
flowchart LR
    A[布局问题] --> B[Flex 一维布局]
    A --> C[Grid 二维布局]
    B --> D[更适合单行或单列的排列与对齐]
    C --> E[更适合同时控制行和列]

13. 响应式设计到底在解决什么问题

响应式不是“页面缩一缩就行”,而是在解决:同一份内容,如何在不同屏幕尺寸和设备环境下保持可读、可用和稳定。

最常见的手段包括:

  1. 弹性布局
  2. 百分比和相对单位
  3. 媒体查询
  4. 图片和容器自适应

例如:

css
.container {
  width: min(100% - 32px, 1200px);
  margin: 0 auto;
}

@media (max-width: 768px) {
  .sidebar {
    display: none;
  }
}

13.1 常见单位怎么选

常见单位包括:

  1. px
  2. %
  3. em
  4. rem
  5. vw
  6. vh

它们分别更适合不同问题:

  1. px 适合明确尺寸
  2. % 适合相对父容器比例
  3. rem 更适合和根字体联动的统一缩放
  4. vwvh 更适合和视口尺寸直接关联

14. 动画和过渡应该怎么理解

这部分不是“做点花哨效果”,而是在表达:状态变化时,界面如何更自然地从一种状态过渡到另一种状态。

最常见的两种方式是:

  1. transition
  2. animation

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 检查清单

写一个页面时,至少可以自查下面这些问题:

  1. 这条样式是否真的命中了目标元素
  2. 是否被更高优先级规则覆盖了
  3. 元素当前是否还在正常文档流中
  4. 盒模型大小是否符合预期
  5. Flex 还是 Grid 是否合理
  6. 是否考虑了不同屏幕尺寸下的表现
  7. 动画和过渡是否真的在帮助理解,而不是制造干扰

17. 小结

如果把 CSS 压缩成一句话,可以记住:CSS 负责定义页面的视觉样式、空间布局和状态变化,是把 HTML 骨架真正变成界面的关键一层。

如果继续往下读,最自然的下一步是进入 JavaScript,因为页面有了结构和样式之后,接下来就该看它如何响应用户交互和执行业务逻辑。

基于 VitePress 构建的个人技术笔记。