CSS 面试真题补充:布局边界、渲染与性能
根据编号 12《CSS 面试真题》补充响应式、居中、选择器、隐藏、动画、Flex/Grid、像素、回流重绘和性能场景。
CSS 面试真题补充:布局边界、渲染与性能
本文根据编号 12《CSS 面试真题》整理。项目已有 CSS 专题文章覆盖各属性的基础用法,这里保留 PDF 中 20 道题的高频追问和容易踩坑的工程判断。
1. 响应式尺寸:先确认参照物
百分比不是“相对于屏幕”的统一单位,参照物取决于属性和包含块:
width、height通常相对包含块的尺寸计算;padding和margin的百分比在传统 CSS 规则中都以包含块的宽度为参照,即使写的是padding-top;- 绝对定位元素的
top/right/bottom/left参照最近的定位祖先; vw、vh直接相对视口宽高;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;
}
}
继承只适用于可继承属性,例如 color、font-family;width、height、margin、padding 和 border 默认不继承。伪元素 ::before、::after 生成的内容依附于宿主元素,常用于装饰,不应承载关键语义文本。
5. 隐藏元素时同时考虑布局和无障碍
| 方式 | 占位 | 默认可交互 | 适合 |
|---|---|---|---|
display: none |
否 | 否 | 真正不存在的分支 |
visibility: hidden |
是 | 否 | 保持布局占位 |
opacity: 0 |
是 | 是 | 淡入淡出,需额外禁用交互 |
| 移到视口外 | 否 | 可能 | 屏幕阅读器可访问的辅助内容 |
clip-path / clip |
是 | 通常否 | 视觉隐藏 |
opacity: 0 的元素仍可能接收点击、获得焦点或被读屏器读取。模态框关闭时,除了透明度,还要管理 pointer-events、焦点和 aria-hidden;只写 opacity: 0 容易留下“看不见但能点”的交互陷阱。
需要动画折叠内容时,可以让 max-height、transform 或 opacity 参与过渡;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 容器以及非 visible 的 overflow。它可以:
- 让容器计算浮动子元素的高度;
- 使内容避开外部浮动元素;
- 把内部布局与外部 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;
}
优先动画 transform 和 opacity,但不要为了“上 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-content、justify-items 和 justify-self 混为一谈:前者分配整个网格,后两者控制项目在网格区域内的对齐。(深入阅读:Grid 与 Flexbox、Flex 简写)
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 结构通常需要回流,改变颜色和背景通常只需重绘;transform 和 opacity 在合适条件下可以只进入合成阶段。读取 offsetWidth、getBoundingClientRect() 或 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 性能优化的回答框架
可以从加载、匹配、布局和资源四层回答:
- 加载:删除无用 CSS,拆分首屏关键样式,避免不必要的
@import,使用缓存和压缩。 - 匹配:保持选择器短而稳定,避免过深的后代选择器和大范围通配符。
- 布局:批量读写 DOM,减少频繁改变几何属性,优先
transform/opacity做动画。 - 资源:压缩图片和字体,按需加载,必要时使用
contain或组件边界限制影响范围。
优化前后应记录 CSS 体积、首次内容绘制、长任务和交互延迟;只说“用了 GPU”而没有指标,不能证明优化有效。(深入阅读:CSS 性能优化维度)
Q&A 索引
本页的短答已合并到同目录的 99-高频追问Q&A.md;本页保留 PDF 中需要展开说明的布局、渲染和性能场景,避免重复维护。