1. CSS 选择器优先级:不是谁写得多,而是谁“说了算”
你有没有遇到过这种情况:引入了一个 UI 框架,想改个按钮样式,结果发现自己的 CSS 根本没生效?打开开发者工具一看,你的样式被划掉了。这时候,问题往往出在——优先级不够。
CSS 的优先级,本质上是一场“权力斗争”。多个规则作用于同一个元素时,浏览器得有个标准来决定用哪个。这个标准,就是“特异性”(Specificity)。
我们可以把优先级想象成一个“权重打分系统”,从高到低大致是:
!important
> 内联样式(style 属性) > ID 选择器 > 类/属性/伪类选择器 > 标签/伪元素选择器
但面试官如果只让你背这个顺序,那太浅了。真正关键的是理解“权重怎么算”。
举个例子:
/* 权重:100(ID) */
#header .nav a { color: blue; }
/* 权重:20(两个类) */
.sidebar .menu a { color: red; }
虽然第二个选择器更长,但它的权重只有 20,而第一个是 100,所以蓝色会胜出。
再比如:
/* 权重:111(1个ID + 1个类 + 1个标签) */
#main .btn span { font-weight: bold; }
/* 权重:100(只有ID) */
#main { font-weight: normal; }
即便 #main
更“全局”,但具体到 span
上,前者的权重更高,粗体依然生效。
⚠️ 面试加分点:别滥用 !important
!important
虽然能强行获胜,但它就像“核武器”——用一次,代码的可维护性就下降一分。一旦项目里到处都是 !important
,你就进入了“重要性战争”,最后谁写得晚谁赢,完全失控。
更优雅的做法是:
- 提高选择器的具体性(比如加个父级类)
- 利用 CSS 的层叠顺序(后引入的样式优先级更高)
- 或者在框架允许的情况下,使用 CSS 变量 或 scoped 样式
2. CSS 单位:px、em、rem、vw、vh——选对单位,布局事半功倍
单位是 CSS 中最灵活也最容易踩坑的部分。不同的单位适用于不同的场景,选错了,响应式就变成“错位式”。
我们一个一个来看:
✅ px
(像素)——绝对中的“相对”
px
是最熟悉的单位,它是“绝对单位”,但在高分辨率屏幕(比如 Retina 屏)上,1 个 CSS 像素可能对应多个物理像素(DPR > 1)。所以你写的 1px
边框在 iPhone 上看起来特别粗。如果要做真正的“高清 1px”,得用 transform: scale(0.5)
或 viewport
缩放。
✅ em
——相对当前字体,但会“层层放大”
em
的基准是当前元素的 font-size
。它的好处是能和字体保持比例,比如按钮的 padding 用 em
,字体变大时,按钮也自动变大。但它的坑在于继承和嵌套:如果父元素 font-size: 1.2em
,子元素再 1.2em
,结果就是 1.44em
,容易“滚雪球”式放大。
✅ rem
——基于根元素,响应式排版的利器
rem
的“r”代表 root,它的基准是 <html>
元素的 font-size
。无论嵌套多深,1rem
永远等于根字体大小。这使得 rem
成为实现全局响应式的首选。比如我可以在不同屏幕宽度下动态设置:
/* 手机端 */
html { font-size: 14px; }
/* 桌面端 */
@media (min-width: 768px) {
html { font-size: 16px; }
}
整个页面的字体和间距就会等比缩放,非常优雅。
✅ vw
/ vh
——视口单位,流式布局的好帮手
1vw = 视口宽度的 1%
,1vh = 视口高度的 1%
。它们特别适合做全屏背景、流式容器。但有个大坑:在 iOS Safari 上,地址栏会动态显示/隐藏,导致视口高度变化。你写的 100vh
可能比实际可用空间还大,造成页面滚动或布局抖动。
解决方案:
- 使用
dvh
(dynamic viewport height,现代浏览器支持) - 或用 JavaScript 动态计算并设置高度
3. 隐藏元素的几种方式:不只是“看不见”那么简单
面试官常问:“怎么隐藏一个元素?它们有啥区别?” 这题看似简单,但能看出你对布局和交互的理解。
方法 | 占文档流 | 响应事件 | 典型场景 |
---|---|---|---|
display: none | ❌ 不占空间 | ❌ 不可点击 | 彻底隐藏,比如 Tab 切换 |
visibility: hidden | ✅ 占空间 | ❌ 不可点击 | 隐藏但保留位置,比如 loading 占位 |
opacity: 0 | ✅ 占空间 | ✅ 可点击 | 做淡入淡出动画,避免布局跳动 |
width: 0; height: 0 | ❌ 不占空间 | ❌ 不可点击 | 内容收起,比如折叠面板 |
clip-path: polygon(...) | ✅ 占空间 | ❌ 不可点击 | 精确裁剪,动画友好 |
💡 实战建议:
- 做动画时优先用
opacity
,因为它不触发重排,性能好。 - 想彻底移除空间用
display: none
。 - 如果只是想让用户看不见但保留布局,用
visibility: hidden
。
4. 盒模型(Box Model):每个元素都是一个盒子,但“盒子”有两种理解
在 CSS 中,每个元素都由 content、padding、border、margin 构成。但关键在于:width
和 height
到底包含哪些部分?
📦 标准盒模型(content-box
,默认)
width
/height
只包含 content- 实际占用宽高 = content + padding + border + margin
- 优点:符合 W3C 标准
- 缺点:布局时要手动减去 padding 和 border,容易出错
📦 怪异盒模型(border-box
)
width
/height
包含 content + padding + border- 实际占用宽高 = width/height + margin
- 优点:布局直观,
width: 300px
就是 300px - 缺点:与标准模型不一致
🛠 实战建议:
我几乎在每个项目初始化时都会写:
* {
box-sizing: border-box;
}
这能避免大量尺寸计算错误,减少重绘和重排,提升开发效率和页面性能。同时记住:
- 背景色只延伸到 padding 区域
- margin 会发生折叠(垂直方向相邻元素的 margin 会合并)
5. BFC(块级格式化上下文):CSS 布局的“隔离舱”
BFC(Block Formatting Context)是 CSS 中一个非常重要的概念,它是一个独立的渲染区域,里面的元素布局不会影响外面。
🔧 什么情况下会触发 BFC?
float
不为none
overflow
为hidden
、auto
、scroll
display
为inline-block
、flex
、grid
、table-cell
position
为absolute
、fixed
🎯 BFC 的核心特性:
- 内部盒子垂直排列
- 防止与浮动元素重叠(可用于清除浮动)
- 计算高度时包含浮动子元素(解决父容器高度塌陷)
- 外部 margin 不与内部 margin 合并(解决外边距塌陷)
💼 典型应用场景:
- 清除浮动:给父容器加
overflow: hidden
- 避免文字环绕浮动图片:给文字容器触发 BFC
- 解决 margin 合并:给相邻元素加 BFC
6. 移动端适配实战技巧:不只是 rem
结合上面的知识,移动端适配的核心思路是:
✅ 使用 rem
+ 动态 html
字体
// 根据屏幕宽度动态设置 font-size
function setRootFontSize() {
const width = Math.min(window.innerWidth, 750);
document.documentElement.style.fontSize = `${width / 7.5}px`;
}
window.addEventListener('resize', setRootFontSize);
setRootFontSize();
✅ 配合 vw
做流式容器
.container {
width: 90vw; /* 占视口 90% */
max-width: 750px;
}
✅ 解决 iOS Safari 100vh
抖动
// 动态设置高度,避免地址栏影响
document.documentElement.style.setProperty('--vh', window.innerHeight * 0.01 + 'px');
.full-height {
height: calc(var(--vh, 1vh) * 100);
}