跳到主要内容

CSS 热门面试题

使用说明

本篇共 60 道题。

CSS 面试重点通常不是背属性,而是能解释布局规则、层叠关系、渲染代价和方案取舍。下面的答案按口头回答组织,复杂题再补场景。

Q1: 标准盒模型和 IE 盒模型有什么区别?

答案

区别在 widthheight 是否包含内边距与边框。

  • content-box 中设置的是内容区尺寸,最终占用还要加 paddingborder
  • border-box 中设置的是边框盒尺寸,内容区会自动扣除内边距和边框。
  • 工程里通常全局使用 box-sizing: border-box,组件尺寸更容易推算。

Q2: 什么是 BFC?它能解决什么问题?

答案

问题BFC 解决原理
浮动子元素导致父元素高度坍塌BFC 会包含内部浮动元素
垂直方向 margin 合并不同 BFC 之间不会发生 margin 合并
浮动元素覆盖相邻元素BFC 不与浮动元素重叠
父子元素 margin 穿透BFC 创建独立容器,margin 不会穿透

Q3: Flex 布局中 flex: 1 通常表示什么?

答案

常见浏览器行为下它等价于让项目可增长、可收缩,并把基础尺寸设为零附近,也就是按剩余空间分配,而不是按内容原始宽度分配。

还要注意 Flex 项目默认 min-width: auto,长文本可能不肯缩小;需要截断时常配 min-width: 0

Q4: Flex 和 Grid 怎么选?

答案

场景推荐原因
导航栏项目排列Flex一维、内容驱动
卡片网格Grid二维、需要对齐行列
表单布局Grid标签和输入框需要对齐
等高列都可以Grid 更直接
页面整体结构Gridheader/sidebar/main/footer
按钮组Flex简单一维排列
仪表盘Grid复杂二维 + 合并区域

经验法则:从内向外用 Flex,从外向内用 Grid

Q5: CSS 选择器优先级怎么计算?

答案

可以按内联样式、ID、类/属性/伪类、元素/伪元素四级理解,同级再比较出现顺序。

!important 会改变普通层叠优先关系,但不应作为日常覆盖工具。更可维护的方式是控制作用域、选择器复杂度和 Cascade Layers,而不是不断叠加权重。

Q6: position: absolute 相对谁定位?

答案

绝对定位元素会相对它的包含块定位。常见情况下,包含块由最近一个 position 不为 static 的祖先元素建立,定位边界通常是该祖先的 padding box;如果没有这样的祖先,则相对初始包含块定位。

但面试时最好补充:包含块不只由 position 建立,某些 transformfiltercontain 等属性也可能为后代建立包含块。因此排查定位偏差时,要沿祖先链检查这些属性,而不是只找 position: relative

绝对定位会脱离正常文档流,但它的尺寸仍可能由 left/right/top/bottom 和内容共同决定。

Q7: position: sticky 为什么会失效?

答案

常见原因是没有设置 top 等偏移、祖先滚动容器不是预期元素、祖先的 overflow 改变了滚动上下文,或可滚动空间不足。

排查时先确认它相对哪个容器粘住,再检查祖先尺寸、overflow 和自身所在布局,不要先用更高 z-index 猜问题。

Q8: 水平垂直居中有哪些可靠方案?

答案

现代布局首选 Flex 或 Grid:父容器用 display: flex; align-items: center; justify-content: center,或者 Grid 的 place-items: center

绝对定位加 transform 适合覆盖层;文本单行居中可用行高。回答时应先确认是否已知尺寸、是否脱离文档流和是否要兼容多行内容。

Q9: 什么是 margin 折叠?

答案

垂直方向上相邻的 margin 会发生合并,取较大值而非叠加。有三种场景:

  1. 相邻兄弟元素的上下 margin
  2. 父元素与第一个/最后一个子元素的 margin
  3. 空块元素自身的上下 margin

解决方式:

  • 创建 BFC(overflow: hidden/display: flow-root
  • 设置 borderpadding 隔开
  • 使用 Flex/Grid 布局
  • 改为 inline-block

Q10: display: nonevisibility: hiddenopacity: 0 有什么区别?

答案

特性display: nonevisibility: hiddenopacity: 0
是否占据布局空间
是否参与绘制不绘制内容会参与合成,只是完全透明
是否响应指针事件通常否默认仍会
是否可聚焦可能仍可
是否适合透明度过渡可与其他属性组合

因此“看不见”不等于“不可交互”。用 opacity: 0 隐藏控件时,通常还要处理 pointer-events、焦点和可访问性;如果内容应完全退出页面结构,使用 hiddendisplay: none 更合适。

Q11: 什么是层叠上下文?为什么 z-index 很大也没用?

答案

层叠上下文是独立的绘制层级单元,子元素的 z-index 只能在自己所在上下文内比较,无法越过父级与外部兄弟竞争。

定位元素、opacity、小于 1、transform、isolation 等都可能创建上下文。排查时看祖先上下文,而不是不断把数值加大。

Q12: 回流和重绘有什么区别?

答案

回流是几何信息变化后重新计算布局,通常会连带重绘;重绘是外观变化但布局不变,例如颜色改变。

批量读取/写入布局属性、避免循环中交替访问 offsetWidth 和修改样式,可减少强制同步布局。动画优先用 transform 和 opacity,但仍要关注合成层数量。

Q13: 为什么 transform 动画通常更流畅?

答案

transform 和 opacity 往往可以在合成阶段更新,避免主线程反复布局和大面积绘制,因此更适合位移和淡入淡出。

这不是绝对“走 GPU 就免费”。大图层会占显存,滤镜、阴影和复杂绘制仍可能昂贵,will-change 也只应短期、精确使用。

Q14: 响应式设计的核心思路是什么?

答案

让布局根据可用空间和内容能力逐步适配,而不是为每个设备型号写一套页面。

  • 使用弹性布局、相对单位、响应式图片和少量内容驱动断点。
  • 优先移动端基础样式,再通过媒体查询增强大屏体验。
  • 组件级适配可考虑 Container Queries,避免完全依赖页面视口。

Q15: pxrememvw 怎么选?

答案

px 适合明确边框和细粒度尺寸;rem 相对根字体,适合全局尺度和可访问缩放;em 相对当前元素字体,适合组件内部比例;vw 相对视口,适合流体尺寸但要设置上下限。

实际项目通常混合使用,并用 clamp() 控制流体值,避免超宽或超窄屏失控。

Q16: CSS 变量相比预处理器变量有什么不同?

答案

CSS 自定义属性存在于运行时,参与层叠和继承,可以被媒体查询、主题容器和 JavaScript 动态修改;Sass 等变量在构建时展开,运行时不存在。

主题 Token 更适合 CSS 变量,复杂生成逻辑可由预处理器完成,二者可以配合。

Q17: 伪类和伪元素有什么区别?

答案

特性伪类(Pseudo-class)伪元素(Pseudo-element)
语法:hover(单冒号)::before(双冒号)
作用选择元素的状态创建虚拟元素
是否创建 DOM是(虚拟 DOM 节点)
数量可以叠加多个同类型只能一个
示例:hover:nth-child::before::after

Q18: CSS Modules、CSS-in-JS 和原子化 CSS 怎么选?

答案

特性CSS ModulesCSS-in-JS
文件独立 .module.css写在 JS/TS 中
运行时有(Runtime 方案)
动态样式通过 className 切换通过 props 动态生成
学习成本低(就是 CSS)中(新的 API)
适用框架通用主要 React

CSS Modules 更轻量、无运行时,适合不需要高度动态样式的项目。

Q19: 如何降低 CSS 对首屏性能的影响?

答案

控制关键 CSS 体积和加载顺序,删除无用样式,避免巨大的全局选择器与重复框架样式。

按路由或组件拆分非关键样式,压缩产物,谨慎内联关键 CSS。同时监控样式引起的布局偏移和长时间样式计算,而不只看文件大小。

  • 加载阶段:抽取并尽早加载首屏 Critical CSS,其余样式按路由或组件拆分。
  • 体积阶段:清理未使用规则、压缩产物,避免重复引入组件库主题。
  • 运行阶段:复杂选择器通常不是首要问题,更应关注会阻塞渲染的样式体积和动态布局成本。

Q20: containcontent-visibility 有什么价值?

答案

contain 告诉浏览器某个子树在布局、绘制等方面相对独立,缩小失效影响;content-visibility: auto 可以跳过屏外内容的布局和绘制。

它们适合长页面和独立组件,但要提供合理的占位尺寸,并验证查找、焦点跳转和可访问性行为。

Q21: inheritinitialunsetrevert 有什么区别?

答案

  • inherit:强制取父元素的计算值,不管该属性默认是否继承。
  • initial:恢复为 CSS 规范定义的初始值,不等于浏览器默认样式。
  • unset:可继承属性按 inherit 处理,不可继承属性按 initial 处理。
  • revert:回退当前来源的声明,让更低优先级来源或用户代理样式重新生效。
  • revert-layer:只回退当前 Cascade Layer,保留其他层的结果。

组件库做样式重置时要先明确希望“继承父级”“回到规范初值”还是“恢复浏览器默认表现”,不能把这些值混用。

Q22: Flex 项目为什么经常需要设置 min-width: 0

答案

Flex 项目的默认最小尺寸通常是 min-width: auto,它会参考内容的最小固有宽度。长单词、表格或设置了 white-space: nowrap 的文本可能因此拒绝收缩,把容器撑破。

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

min-width: 0 允许项目缩小到内容固有宽度以下,省略号才有机会生效。纵向 Flex 布局出现类似溢出时,对应检查 min-height: 0

Q23: Flex 容器的属性有哪些?

答案

6 个容器属性 + 1 个间距属性:

属性作用默认值
flex-direction主轴方向row
flex-wrap是否换行nowrap
flex-flowdirection + wrap 简写row nowrap
justify-content主轴对齐方式flex-start
align-items交叉轴对齐(单行)stretch
align-content交叉轴对齐(多行)stretch
gap项目间距0

Q24: Grid 布局的核心概念有哪些?

答案

核心概念包括:

  • Grid Container / Item:容器和直接子元素
  • Grid Line:网格线,用数字或命名引用
  • Grid Track:一行或一列
  • Grid Cell:最小单元格
  • Grid Area:一个或多个 cell 组成的矩形区域
  • fr 单位:可用空间的比例份额
  • gap:行列间距

Q25: min-contentmax-contentfit-content 怎么理解?

答案

它们描述元素的固有尺寸:

  • min-content:在允许换行的前提下尽可能窄,通常接近最长不可断片段。
  • max-content:内容完全不换行时所需的宽度。
  • fit-content:在可用空间、最小内容尺寸和最大内容尺寸之间取一个合适结果。
  • Grid 的 fit-content(<length>) 还可以给轨道设置上限。

这组值适合自适应标签、侧栏和内容驱动的 Grid 轨道。使用时要测试超长单词、国际化文本和可替换元素,不能只用短中文样例判断。

Q26: position 有哪些值?分别什么含义?

答案

5 个值:static(默认,正常流)、relative(相对自身偏移)、absolute(相对非 static 祖先)、fixed(相对视口)、sticky(滚动吸附)。

其中 absolutefixed 脱离文档流relativesticky 不脱离

Q27: :is():where() 有什么区别?

答案

二者都能把一组选项写进一个选择器,主要差异是优先级:

  • :is() 的优先级取参数列表中最高的那一个。
  • :where() 自身及其参数的优先级始终为零。
  • 两者都会按“宽容选择器列表”处理,不支持的分支通常不会让整个列表失效。

组件库的基础样式常用 :where() 保持易覆盖;业务条件选择可用 :is()。如果把 ID 放进 :is(),即使当前匹配的是另一分支,也可能显著抬高整个选择器的优先级。

Q28: 百分比高度为什么经常不生效?

答案

百分比高度需要从包含块得到可确定的高度。如果父元素的 height 仍是由内容撑开的 auto,子元素写 height: 100% 往往没有可计算的基准,所以不会得到预期的满高效果。

常见处理方式:

  • 页面级满高可为 htmlbody 和应用根节点建立明确高度,或直接使用 min-height: 100dvh
  • Flex/Grid 布局通常让容器确定可用空间,再通过 flex: 1 或网格轨道分配。
  • 只要求“至少占满”时用 min-height,避免固定高度导致内容溢出。
  • 调试时沿包含块逐层检查高度是否可确定,同时留意绝对定位元素的包含块规则。

Q29: 为什么浮动会导致父元素高度塌陷?

答案

浮动元素脱离了正常文档流,父元素在计算高度时不会将浮动子元素纳入计算,因此如果所有子元素都浮动,父元素的高度就会变为 0。

这不是 bug 而是设计如此——float 的本意是文字环绕,浮动元素不影响块级容器的高度,但行内内容会围绕它排列。

Q30: transition 和 animation 的区别?

答案

核心区别:

  • transition 需要触发条件:hover、JS 改变属性),只有起始和结束两个状态
  • animation 自动播放,可通过 @keyframes 定义多个中间状态,支持循环、暂停

简单交互(悬停变色、展开菜单)用 transition; 复杂动画(加载动画、入场动画)用 animation

Q31: 原生 CSS Nesting 和 Sass 嵌套有什么边界差异?

答案

原生 CSS Nesting 在浏览器运行时直接参与 CSS 解析和层叠,不需要预处理;Sass 嵌套在构建阶段展开,还支持变量、Mixin、循环等编程能力。

实践中两者都要避免过深嵌套,因为展开后会形成高耦合、难覆盖的长选择器。使用 & 时应关注它代表父选择器整体,而不是字符串拼接工具;某些 Sass 的拼接写法不能直接迁移到原生 Nesting。

迁移时应以目标浏览器和构建链为准,通过 Browserslist/PostCSS 做兼容,而不是同时启用两套嵌套转换导致重复展开。

Q32: 移动端和多尺寸页面应该怎样做适配?

答案

没有适用于所有页面的“唯一推荐单位”。更稳妥的做法是组合使用:

  1. 用 Flex/Grid 和内容驱动断点建立弹性布局。
  2. 页面级变化使用媒体查询,组件级变化优先考虑容器查询。
  3. 字体与间距可用 rem、百分比和 clamp() 做有上下限的流体缩放。
  4. 图片使用 srcset/sizes,同时处理安全区域、横竖屏和输入方式。
  5. 通过真实设备与极端内容验证,不根据某个设计稿宽度全局等比缩放。

vwrem 转换可以是特定业务条件下的工程方案,但要限制最小/最大尺寸,并保证用户字体缩放和可访问性不被破坏。

Q33: Sass 和 Less 有什么区别?

答案

核心区别:

  • 变量:Sass 用 $,Less 用 @
  • 编程能力:Sass 更强(完善的条件、循环、模块系统)
  • 编译:Sass 用 Dart Sass,Less 用 JavaScript
  • 生态:Sass 更主流(Bootstrap、Tailwind),Less 在 Ant Design 中使用

Q34: display: contents 有什么作用和风险?

答案

display: contents 会让元素自身不生成布局盒,但它的子元素仍像直接子项一样参与父级布局。它可用于让包装层不干扰 Grid/Flex 排布。

风险在于“没有盒”会影响背景、边框、定位和伪元素;不同浏览器与辅助技术历史上对其可访问性映射也存在过兼容问题。不要仅为了少写一层 CSS 就把有明确语义或交互职责的元素设为 contents

使用前应验证键盘导航、可访问性树和目标浏览器,尤其不要让按钮、表格结构等关键语义依赖它。

Q35: CSS-in-JS 有什么优缺点?

答案

优点:

  • 样式与组件共存,无全局命名冲突
  • 可使用 JS 的变量、函数、条件逻辑
  • 自动添加浏览器前缀
  • 删除组件时样式自动清理,无死代码

缺点:

  • Runtime 方案有性能开销(序列化、注入)
  • 增加包体积(需要运行时库)
  • SSR 需要额外配置
  • DevTools 中类名不易阅读
  • React Server Components 不兼容 Runtime CSS-in-JS

Q36: CSS :has() 有什么用?能举例吗?

答案

:has() 是父选择器,根据子元素或后续兄弟的存在/状态选择当前元素:

/* 表单验证 */
.input-group:has(input:invalid) { border-color: red; }
.input-group:has(input:valid) { border-color: green; }

/* 空状态 */
.list:not(:has(li)) { display: none; } /* 没有 li 时隐藏列表 */
.list:not(:has(li)) + .empty-state { display: block; }

本质上弥补了 CSS 只能"向下"选择的缺陷。

Q37: 哪些 CSS 属性会触发重排?如何避免?

答案

改变元素几何属性的操作会触发重排:widthheightmarginpaddingpositiondisplayfont-size 等。

避免方法:

  1. 动画用 transform 代替 top/left/width
  2. 批量修改 DOM,避免逐条操作
  3. 使用 contain 限制重排范围
  4. 使用 documentFragment 或离屏 DOM

Q38: 圣杯布局和双飞翼布局的区别?

答案

特性圣杯布局双飞翼布局
HTML 结构3 个并列元素main 需要额外 wrapper
占位方式父容器 paddingmain 内部 margin
定位方式负 margin + position: relative只需负 margin
主内容优先✅ DOM 最先✅ DOM 最先
复杂度较高稍低

两者目的相同:中间列 DOM 优先加载,左右固定宽度。现代方案直接用 Flex/Grid。

Q39: 容器查询和媒体查询应该怎样分工?

答案

媒体查询根据视口或设备环境决定页面级布局,适合导航形态、整页栏数和用户偏好;容器查询根据组件容器的可用尺寸或样式状态调整组件,适合可复用卡片、侧栏模块和嵌入式组件。

使用尺寸容器查询时,先在容器上声明 container-type

.card-list {
container-type: inline-size;
}

@container (min-width: 32rem) {
.card {
grid-template-columns: 10rem 1fr;
}
}

不要把所有断点机械迁移成容器查询。页面外壳仍由媒体查询控制,内部组件再根据自身空间响应,职责更清晰。

Q40: overflow: hiddenoverflow: clip 有什么区别?

答案

两者都能裁剪超出 padding box 的内容,但 hidden 会建立可滚动容器,只是没有可见滚动条,内容仍可能通过脚本或焦点滚动;clip 不提供滚动机制,也不能通过 scrollTop 正常滚到被裁剪区域。

overflow: hidden 还常被用于建立 BFC,而 clip 本身不应被当作同样的 BFC 技巧;需要隔离布局时可配合 display: flow-root

选择时先判断是“需要可编程滚动但隐藏滚动条”,还是“内容永久裁掉”。焦点可能进入不可见区域时要特别谨慎。

Q41: Flex 布局中的 gap 和子元素 margin 有什么区别?

答案

gap 表示 Flex/Grid 项目之间的间距,只在相邻项目或轨道之间出现,不会自动给容器外边缘增加一圈间距;margin 属于元素自身,会参与外边距、自动 margin 和方向性布局计算。

实际选择时:

  • 统一的行列间距优先使用 gap,不需要为首尾元素清零,也更适合换行布局。
  • 某个项目需要单独偏移或用 margin-inline-start: auto 占据剩余空间时使用 margin。
  • gap 不会发生 margin collapse,也不能替代容器 padding。
  • 兼容旧环境时要确认 Flex gap 支持情况,而不是只看 Grid gap。

Q42: fr 单位是什么?和百分比有什么区别?

答案

fr 代表 fraction(分数),表示剩余空间的比例:

特性fr%
参考基准剩余可用空间容器宽度
是否考虑 gap是(自动扣除)否(可能溢出)
溢出风险高(如 3 × 33.33% + gap 会溢出)
/* 使用百分比:加上 gap 后会溢出 */
grid-template-columns: 33.33% 33.33% 33.33%; /* + gap = 超出 100% */

/* 使用 fr:自动扣除 gap 后分配 */
grid-template-columns: 1fr 1fr 1fr; /* 完美 */

Q43: aspect-ratio 如何减少布局偏移?

答案

aspect-ratio 在资源内容尚未加载时就为元素建立宽高比例,浏览器可以提前预留空间,减少图片、视频或异步卡片加载造成的 CLS。

.video {
width: 100%;
aspect-ratio: 16 / 9;
}

对图片优先写真实的 widthheight 属性,浏览器会推导固有比例;CSS 的 aspect-ratio 更适合响应式容器和非图片元素。若同时给出明确宽高,比例只在存在自动尺寸的轴上参与计算。

Q44: 为什么设置 transform 后,后代的 position: fixed 可能不再相对视口?

答案

某些会建立包含块的祖先属性,例如非 nonetransformperspective、部分 filtercontain,可能让后代 fixed 元素改为相对该祖先定位。

这会导致弹窗、吸顶层随着局部容器滚动或被其裁剪。排查步骤是沿祖先链检查包含块、overflow、层叠上下文和 Top Layer。

全局模态框通常放到应用根节点或使用 Portal;能用原生 dialog/Popover 的场景还可以利用 Top Layer 避开普通层叠上下文。

Q45: 多个 !important 声明冲突时怎么比较?

答案

!important 不是“无条件最大”。两个重要声明冲突时,仍要按来源与层、作用域接近度、选择器优先级、源码顺序继续比较。

需要注意两点:

  • 用户的重要样式可以覆盖作者的重要样式,这是可访问性设计的一部分。
  • Cascade Layers 在重要声明下的层顺序与普通声明相反,较早声明的层更有保护能力。

工程上应先通过 Layer、作用域和组件 API 管理覆盖关系,只在确实需要保护的约束上使用 !important,不要靠不断增加选择器权重解决架构问题。

Q46: 移动端 1px 边框问题怎么解决?

答案

高 DPR 设备上 1px CSS 像素可能显示为 2-3 物理像素,看起来过粗。解决方案:

/* 方案1: transform 缩放(推荐) */
.border-1px::after {
content: '';
position: absolute;
left: 0; top: 0;
width: 200%; height: 200%;
border: 1px solid #ccc;
transform: scale(0.5);
transform-origin: 0 0;
pointer-events: none;
}

/* 方案2: 0.5px(仅 iOS Safari 支持) */
.border { border-width: 0.5px; }

/* 方案3: box-shadow */
.border { box-shadow: 0 0 0 0.5px #ccc; }

Q47: object-fitobject-position 应该怎样配合使用?

答案

object-fit 决定图片或视频怎样放进元素的内容盒,object-position 决定裁剪或留白发生时内容对齐到哪里。

  • cover:填满盒子并保持比例,可能裁剪,常用于封面图。
  • contain:完整展示并保持比例,可能留白,常用于商品图或预览。
  • fill:直接拉伸到盒子,可能变形。
  • none / scale-down:保留固有尺寸,或在 nonecontain 中选择更小结果。

使用 cover 时可写 object-position: 50% 20% 保留人物脸部等视觉焦点。前提是替换元素本身有明确尺寸;这两个属性不会替你决定容器宽高,也不能直接作用于普通背景图。

Q48: 哪些 CSS 属性更适合做动画?

答案

通常优先选择 transformopacity,因为在满足分层条件时,它们可以只更新合成结果,避免每帧重新布局和大面积绘制。

但这不是绝对保证:

  • 元素可能仍需首次绘制或重新栅格化。
  • 大图层会增加显存和合成成本。
  • filter、阴影和大面积透明内容可能很昂贵。
  • will-change 只应在动画前短期、精确使用。

判断性能要录制 Performance/Rendering 数据,看是否发生 Layout、Paint、图层膨胀和掉帧,而不是只背“GPU 加速”。

Q49: 如何用纯 CSS 实现暗色模式?

答案

:root {
color-scheme: light dark;
--bg: #fff;
--text: #333;
}

@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #e0e0e0;
}
}

body {
background: var(--bg);
color: var(--text);
}

加上 color-scheme: light dark 让表单元素、滚动条等自动适配。

Q50: 什么是设备像素比(DPR)?

答案

DPR = 设备物理像素 / CSS 逻辑像素。iPhone 14 Pro 的 DPR 是 3,意味着 1 个 CSS 像素对应 3×3 = 9 个物理像素。

获取方式:window.devicePixelRatio

DPR 影响:图片需要提供 2x/3x 版本才能在高 DPR 设备上清晰显示。更多参见图片优化

Q51: 为什么需要 CSS 预处理器?

答案

CSS 本身缺少编程能力,预处理器解决了:

  1. 代码复用:变量、Mixin 避免重复
  2. 可维护性:嵌套、模块化组织代码
  3. 计算能力:函数、运算减少硬编码
  4. 代码组织@use/@import 拆分文件

但随着 CSS 原生支持了变量(var())、嵌套(&)和 calc(),预处理器的必要性正在降低。

Q52: 如何只对屏幕阅读器显示内容?

答案

使用 .sr-only(screen reader only)模式:

.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}

典型用途:为图标按钮提供文字说明、为装饰性图片提供替代文本。

Q53: Tailwind CSS 的优缺点?

答案

优点:

  • 开发效率高,不用起类名
  • 产物体积小(只包含使用的类)
  • 一致的设计系统(间距、颜色)
  • 响应式、暗色模式原生支持
  • 无 CSS 文件增长问题

缺点:

  • 类名冗长,HTML 可读性差
  • 学习成本(需要记忆类名)
  • 复杂样式需要 @apply 或自定义
  • 高度定制的设计较难实现

Q54: @layer 解决什么问题?

答案

解决第三方库样式难以覆盖的问题。传统方式要用更高优先级的选择器或 !important@layer 让你定义样式层级,不管选择器优先级如何,层级顺序决定最终胜出:

@layer third-party, custom;
/* custom 层的样式永远覆盖 third-party 层 */

Tailwind CSS v4 就使用 @layer 组织样式层级。

Q55: CSS Scroll-driven Animations 适合什么场景?

答案

Scroll-driven Animations 用滚动进度驱动 CSS Animation,可以把“进入视口后的揭示”“阅读进度条”和“滚动容器内的时间线”交给浏览器时间轴处理,减少手写高频 scroll 监听。

核心是区分:

  • scroll():使用滚动容器的整体滚动进度。
  • view():使用元素进入和离开滚动视口的可见进度。
  • animation-timeline:把动画绑定到对应时间轴。

它适合视觉增强,不应让关键内容必须依赖动画才能理解。上线前检查目标浏览器,并通过 @supportsprefers-reduced-motion 提供渐进增强与减弱动画方案。

Q56: 如何实现粘性页脚?

答案

最简单的方案:

body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
main { flex: 1; }

mainflex: 1 会撑满剩余空间,footer 自然被推到底部。

Q57: CSS 逻辑属性为什么适合国际化布局?

答案

逻辑属性按书写方向描述布局,而不是固定使用上下左右。例如:

  • margin-inline 对应行内方向两侧。
  • padding-block 对应块方向两侧。
  • inset-inline-start 表示行内起始位置。
  • border-start-start-radius 描述逻辑角。

同一组件切换 LTR、RTL 或竖排书写时,可以随 directionwriting-mode 自动映射,减少成套覆盖。涉及物理方向的图标、拖拽坐标和动画仍需单独判断,不能机械替换所有 left/right

Q58: CSS Subgrid 解决什么布局问题?

答案

普通嵌套 Grid 的轨道彼此独立,多个卡片内部的标题、正文和按钮难以跨卡片对齐。Subgrid 允许子 Grid 复用父 Grid 的列轨或行轨:

.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
}

.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}

它适合表单标签、卡片内容和复杂页面区域的跨层对齐。使用时要明确子项在父网格中跨越的轨道范围,并检查降级布局,不要为了简单一维排列引入 Subgrid。

Q59: flex-shrink 的缩小比例怎么计算?

答案

缩小量与 flex-shrink × flex-basis 的乘积成正比。

溢出量 = 所有项目总宽度 - 容器宽度
项目缩小量 = 溢出量 × (该项目的 shrink × basis) / (所有项目的 shrink × basis 之和)

例如容器 400px,三个项目 A(200px, shrink:1)、B(200px, shrink:2)、C(200px, shrink:1):

  • 溢出 = 600 - 400 = 200px
  • A 权重 = 200×1 = 200,B 权重 = 200×2 = 400,C 权重 = 200×1 = 200
  • A 缩小 = 200 × 200/800 = 50px → 最终 150px
  • B 缩小 = 200 × 400/800 = 100px → 最终 100px
  • C 缩小 = 200 × 200/800 = 50px → 最终 150px

Q60: auto-fillauto-fit 的区别?

答案

两者在项目数量少于可填充列数时表现不同:

  • auto-fill:创建尽可能多的列轨道,多余轨道留空
  • auto-fit:创建列轨道后,多余轨道折叠为 0,已有项目拉伸填满

项目数量恰好填满或大于列数时,两者表现一致

相关链接