跳到正文
前端知识库
CSS

CSS 面试真题补充:布局边界、渲染与性能

根据编号 12《CSS 面试真题》补充响应式、居中、选择器、隐藏、动画、Flex/Grid、像素、回流重绘和性能场景。

10 分钟CSS · 布局 · 响应式 · Flex · Grid · 性能 · 面试

CSS 面试真题补充:布局边界、渲染与性能

本文根据编号 12《CSS 面试真题》整理。项目已有 CSS 专题文章覆盖各属性的基础用法,这里保留 PDF 中 20 道题的高频追问和容易踩坑的工程判断。

1. 响应式尺寸:先确认参照物

百分比不是“相对于屏幕”的统一单位,参照物取决于属性和包含块:

  • widthheight 通常相对包含块的尺寸计算;
  • paddingmargin 的百分比在传统 CSS 规则中都以包含块的宽度为参照,即使写的是 padding-top
  • 绝对定位元素的 top/right/bottom/left 参照最近的定位祖先;
  • vwvh 直接相对视口宽高;
  • rem 相对根元素 html 的字体大小,em 相对当前元素继承后的字体大小。
.card {
  width: min(100%, 32rem);
  padding: 5%; /* 参照包含块宽度,不是自身高度 */
}

响应式布局通常组合媒体查询、流式尺寸和最小/最大约束:

.page {
  padding-inline: 1rem;
}

@media (min-width: 48rem) {
  .page {
    padding-inline: 2rem;
  }
}

不要只按设备型号写大量断点。优先观察布局开始拥挤的宽度,再用 min-width 增强样式;对固定比例的图片或卡片,用 aspect-ratio 防止加载前后的布局跳动。(深入阅读:CSS 单位与响应式尺寸

2. 水平和垂直居中的选择

2.1 已知尺寸的绝对定位

.parent {
  position: relative;
}

.child {
  position: absolute;
  inset: 0;
  width: 8rem;
  height: 4rem;
  margin: auto;
}

2.2 未知尺寸的位移

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

transform 按元素自身尺寸移动,适合子元素尺寸未知的场景;它不会改变文档流中的占位,也会影响层叠和合成层判断。需要让多个项目自然排列时,优先使用 Flex:

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

margin: 0 auto 只解决块级元素的水平外边距,不能单独完成垂直居中。单行文本可以使用合适的 line-height,但多行文本和动态高度不应依赖固定行高“碰巧居中”。(深入阅读:不定宽高居中方案总结

3. 两栏、三栏和旧布局的取舍

现代项目通常用 Flex 或 Grid:

.layout {
  display: grid;
  grid-template-columns: 16rem minmax(0, 1fr);
}

.three-columns {
  display: flex;
  gap: 1rem;
}

.three-columns > :first-child,
.three-columns > :last-child {
  flex: 0 0 12rem;
}

.three-columns > :nth-child(2) {
  min-width: 0;
  flex: 1;
}

minmax(0, 1fr)min-width: 0 很重要:Flex/Grid 子项默认可能按内容的最小尺寸收缩,长单词或不换行文本会把中间列撑破。

圣杯、双飞翼、浮动和 display: table 仍可能出现在旧项目或兼容性题中,但要说明它们的代价:依赖负 margin、DOM 顺序和清除浮动,维护成本高于现代布局。面试时先给可维护的 Flex/Grid 方案,再解释经典方案的原理,不要把历史实现当作默认首选。(深入阅读:三栏布局(左右固定,中间自适应)

4. 选择器、继承与优先级

选择器优先级通常按三列比较:ID、类/属性/伪类、类型/伪元素。它不是简单的十进制相加:

#app .button {}           /* 1-1-0 */
.toolbar .button:hover {} /* 0-3-0 */
button {}                 /* 0-0-1 */

同一优先级再比较来源、级联层和源码顺序。!important 会改变正常优先级,适合极少数基础设施边界,不应作为组件样式冲突的常规修复。(深入阅读:优先级计算

现代 CSS 可以用级联层和低权重选择器管理覆盖关系:

@layer reset, base, components, utilities;

@layer components {
  :where(.button) {
    color: inherit;
  }
}

继承只适用于可继承属性,例如 colorfont-familywidthheightmarginpaddingborder 默认不继承。伪元素 ::before::after 生成的内容依附于宿主元素,常用于装饰,不应承载关键语义文本。

5. 隐藏元素时同时考虑布局和无障碍

方式 占位 默认可交互 适合
display: none 真正不存在的分支
visibility: hidden 保持布局占位
opacity: 0 淡入淡出,需额外禁用交互
移到视口外 可能 屏幕阅读器可访问的辅助内容
clip-path / clip 通常否 视觉隐藏

opacity: 0 的元素仍可能接收点击、获得焦点或被读屏器读取。模态框关闭时,除了透明度,还要管理 pointer-events、焦点和 aria-hidden;只写 opacity: 0 容易留下“看不见但能点”的交互陷阱。

需要动画折叠内容时,可以让 max-heighttransformopacity 参与过渡;display: none 不能直接做 CSS transition,因为它不是可插值的连续值。(深入阅读:隐藏方式对比

6. 文本溢出与可变宽度

单行省略需要三个条件:

.single-line {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

在 Flex 或 Grid 中,min-width: 0 往往是省略号不生效的真正原因。多行省略可以使用:

.multi-line {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

伪元素模拟省略号对背景色、字体和最后一行位置敏感,不如 line-clamp 稳定。若文本是关键内容,应提供展开入口或完整文本,而不是仅依赖视觉截断。(深入阅读:单行文本溢出省略

7. BFC 与浮动场景

BFC 是相互隔离的块级格式化上下文。常见触发方式包括 display: flow-root、浮动、绝对定位、Flex/Grid 容器以及非 visibleoverflow。它可以:

  • 让容器计算浮动子元素的高度;
  • 使内容避开外部浮动元素;
  • 把内部布局与外部 margin 影响隔离。

现代清除浮动优先使用:

.flow-root {
  display: flow-root;
}

overflow: hidden 会同时裁剪溢出内容,可能截断下拉菜单或阴影;如果只需要建立 BFC,flow-root 更能表达意图。BFC 解决的是布局隔离,不等于层叠上下文,不能用它直接解释所有 z-index 问题。(深入阅读:BFC 的应用场景与解决方案

8. 三角形和纯 CSS 图形

边框三角形依赖“零宽高元素的四条边在中心相交”:

.triangle {
  width: 0;
  height: 0;
  border-inline: 2rem solid transparent;
  border-bottom: 2rem solid #2563eb;
}

要做带边框的气泡箭头,可以叠加伪元素并稍微错开;需要可缩放、复杂形状或语义图标时,SVG 通常比多层 border 更容易维护。回答这题时讲清“零尺寸 + 透明边框 + 可见边框”的原理即可,不必背某一组固定像素。(深入阅读:Border 的本质

9. 视差滚动与移动端退化

background-attachment: fixed 可以让背景相对视口保持固定,配合分屏高度形成简单视差;transform: translateZ()perspective 可以做更复杂的 3D 视差。但移动端浏览器对 fixed 背景、滚动容器和 GPU 合成支持并不完全一致,可能退化为普通滚动或出现性能问题。

工程上应提供降级样式,并避免用视差承载关键内容:

.hero {
  min-height: 100svh;
  background: url('/hero.jpg') center / cover no-repeat;
}

@media (prefers-reduced-motion: reduce), (max-width: 48rem) {
  .hero {
    background-attachment: scroll;
  }
}

移动端应把降级和减少动画偏好视为实现的一部分,而不是仅依赖桌面端的视觉效果。(深入阅读:视差滚动的移动端适配

10. CSS3 动画:transition、transform 和 animation

  • transition 描述从一个状态到另一个状态的过渡,通常由 hover、class 或属性变化触发。
  • transform 改变几何变换,不直接改变文档流中的布局尺寸,适合位移、缩放和旋转。
  • animation 配合 @keyframes 描述独立时间线,可循环、暂停和设置多个关键帧。
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.spinner {
  animation: spin 1s linear infinite;
}

优先动画 transformopacity,但不要为了“上 GPU”给所有元素加 will-change。过多独立图层会增加内存和合成成本。非必要动效应尊重用户偏好:

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

动画方案要同时说明触发方式、合成成本和减少动画偏好,不能只展示关键帧代码。(深入阅读:CSS 实现动画的三种方式

11. Grid 与 Flex 的关键区别

Flex 以一个主轴分配空间,适合工具栏、导航和一维列表;Grid 同时定义行和列,适合页面骨架和二维卡片布局。

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: 1rem;
}

Flex 常问 flex: 1 的含义:它通常展开为 1 1 0%,项目先按零基准分配剩余空间;flex-basis: auto 则会把内容尺寸或 width 纳入基准。align-items 控制单行项目的交叉轴对齐,align-content 主要在有多行/多轨道时分配整个容器中的行。

Grid 的 fr 分配的是可用空间,minmax(0, 1fr) 可以避免最小内容尺寸把轨道撑破。不要把 justify-contentjustify-itemsjustify-self 混为一谈:前者分配整个网格,后两者控制项目在网格区域内的对齐。(深入阅读:Grid 与 FlexboxFlex 简写

12. CSS 像素、设备像素、DPR 与 PPI

  • CSS 像素是布局使用的抽象单位;
  • 设备像素是屏幕实际点阵;
  • devicePixelRatio 近似表示一个 CSS 像素对应的设备像素数量;
  • PPI 是物理屏幕密度,不能直接等同于 DPR。

高 DPR 屏幕上,1px 边框可能映射为多个设备像素。需要绘制清晰的图片或 Canvas 时,要按 DPR 放大实际绘制缓冲区,再用 CSS 尺寸显示;普通布局不要因为设备像素多就把所有尺寸乘以 DPR。(深入阅读:DPR 对开发的影响

13. 小于 12px 的文字

浏览器和系统可能对极小字体做最小字号处理。常见 transform: scale(0.8) 方案只缩小视觉内容,原布局盒子仍按原始字体计算,可能出现间距和对齐不一致:

.tiny {
  display: inline-block;
  font-size: 12px;
  transform: scale(0.8);
  transform-origin: left center;
}

zoom 是非标准属性,可能改变布局尺寸并触发重排,不能作为通用跨浏览器方案。-webkit-text-size-adjust: none 会影响移动端可读性,除非有明确设计约束,不要全局关闭系统字体调整。(深入阅读:transform: scale() 的注意事项

14. 回流、重绘与布局抖动

浏览器大致会经历:

DOM/CSSOM -> Render Tree -> Layout(回流) -> Paint(重绘) -> Composite(合成)

改变尺寸、位置、字体或 DOM 结构通常需要回流,改变颜色和背景通常只需重绘;transformopacity 在合适条件下可以只进入合成阶段。读取 offsetWidthgetBoundingClientRect()getComputedStyle(),紧接着写入布局属性,可能强制浏览器同步完成布局,形成 layout thrashing。

// 先集中读取,再集中写入
const heights = boxes.map((box) => box.offsetHeight)
boxes.forEach((box, index) => {
  box.style.height = `${heights[index] + 8}px`
})

批量修改 class、使用 DocumentFragment 或让动画只修改 transform,通常比在循环中交替读写更稳。性能优化要以 Performance 面板和真实指标为依据,不要把“重绘一定很慢”当成绝对结论。(深入阅读:布局抖动(Layout Thrashing)

15. 预处理器、CSS 变量与加载方式

Sass/SCSS、Less 和 Stylus 在构建期提供变量、嵌套、Mixin 和函数,最终输出普通 CSS;CSS 自定义属性在运行时参与级联,适合主题切换和组件参数:

:root {
  --color-primary: #2563eb;
}

.button {
  color: var(--color-primary);
}

预处理器变量不能在浏览器运行时被动态修改,CSS 变量也不能完全替代构建期的循环、模块化和静态校验。两者可以组合,但应明确哪部分需要运行时变化。

<link rel="stylesheet"> 通常更利于并行加载和缓存;多层 @import 容易形成串行依赖并延迟样式可用时间。关键路径可以内联少量 Critical CSS,非关键样式按需加载,但必须处理加载失败和无 JavaScript 的降级。(深入阅读:预处理器 vs CSS 原生

16. CSS 性能优化的回答框架

可以从加载、匹配、布局和资源四层回答:

  1. 加载:删除无用 CSS,拆分首屏关键样式,避免不必要的 @import,使用缓存和压缩。
  2. 匹配:保持选择器短而稳定,避免过深的后代选择器和大范围通配符。
  3. 布局:批量读写 DOM,减少频繁改变几何属性,优先 transform/opacity 做动画。
  4. 资源:压缩图片和字体,按需加载,必要时使用 contain 或组件边界限制影响范围。

优化前后应记录 CSS 体积、首次内容绘制、长任务和交互延迟;只说“用了 GPU”而没有指标,不能证明优化有效。(深入阅读:CSS 性能优化维度

Q&A 索引

本页的短答已合并到同目录的 99-高频追问Q&A.md;本页保留 PDF 中需要展开说明的布局、渲染和性能场景,避免重复维护。