前端 面试题库

收录真实面试常见问题,答案长度适合口头表达;拿不准时可返回相关主题复习。

51个问题 初级 高级
全部难度 初级 中级 高级
逐题查看 显示全部答案
报告错误

HTML 与 CSS

10个问题
01 怎样在 article、section 与 div 之间选择? 初级 常见 查看答案 ▾ 收起 ▴

内容足够完整,可以单独阅读或进入订阅源、搜索结果和其他页面时,应选择 article。内容只是当前文档中有明确主题的部分,通常还带有说明主题的标题时,应选择 section。容器只服务于布局、样式、测量或脚本挂载时,应保留 div。判断依据是内容所有权,不是外观:卡片形状不会自动成为 article,带边框的区块也不会自动成为 section。组合页面后还要检查标题与地标,因为单独合理的组件仍可能制造结构噪声。

讲清楚了吗?
02 怎样在 CSS 过渡与关键帧动画之间选择? 初级 常见 查看答案 ▾ 收起 ▴

当类名、属性、悬停或焦点状态已经改变某个属性,而且只需从当前值插值到目标值时,应选择过渡。效果需要明确的中间阶段、重复、交替或自动开始时,应选择关键帧。过渡响应变化前后的计算值,动画则通过 animation 属性应用命名关键帧。无论采用哪种机制,业务状态和可访问状态都应独立于动画,这样在动态效果被禁用或取消时,界面仍然正确。

延伸阅读 CSS 动画
讲清楚了吗?
03 怎样在运行时 CSS-in-JS 与构建时提取之间选择? 中级 偶尔 查看答案 ▾ 收起 ▴

先列出组件必须表达的值。尺寸、色调和禁用状态等有限状态,通常适合提取类名或数据属性选择器。高基数值往往可以通过 CSS 自定义属性传入,不必在运行时生成规则。只有实时计算 JavaScript 能带来明确收益时,才选择运行时引擎,并把缓存、客户端成本、服务端收集器、CSP 支持和升级路径纳入决策。应比较实际路由的生产资源和浏览器轨迹,不要照搬其他项目的包体积或耗时数字。

延伸阅读 CSS-in-JS
讲清楚了吗?
04 客户端与服务器端表单验证怎样划分职责? 中级 常见 查看答案 ▾ 收起 ▴

客户端验证负责尽早提供与字段相关的反馈,并阻止明显无效的提交,但它运行在用户可控制的环境中。应使用原生 HTML 约束表达基础规则,只补充必要的跨字段或异步检查,并把错误与控件关联。服务器把每个请求都视为不可信数据,解析预期结构,验证完整业务契约,检查权限与当前状态,并在写入附近执行并发不变量。共享模式可以减少重复,但服务器绝不信任客户端声称“已经验证”的标志。验证也不能替代输出编码、参数化查询、CSRF 防护或速率限制。

延伸阅读 表单验证
讲清楚了吗?
05 Sass 变量与 CSS 自定义属性有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

Sass 变量在编译期间求值,随后消失在生成的 CSS 中。它可以保存 Sass 映射、列表、颜色和带单位数字,也能驱动循环或函数。CSS 自定义属性会保留在样式表里,参与层叠与继承,并能随 DOM 状态、媒体条件或 JavaScript 改变。构建期结构和有限规则生成适合使用 Sass 变量;主题值或加载后仍需变化的组件值则应保留为自定义属性,最后检查输出中的 var() 是否仍然存在。

延伸阅读 Sass
讲清楚了吗?
36 为什么不应让 animation-fill-mode 负责元素的持久状态? 中级 偶尔 查看答案 ▾ 收起 ▴

在 CSS Animations Level 1 中,animation-fill-mode: forwards 只是让已结束的动画效果继续参与层叠,并不会把终点值写入元素的普通规则。移除动画名称、改变层叠优先级或启动另一段动画后,底层值仍会显现。打开、关闭或完成等持久状态应由 class 或 attribute 规则表达,动画只负责状态之间的过渡。这样会重复声明终点,但若 JavaScript 必须等 animationend 才提交业务状态,动画被取消或根本未生成时流程就会卡住。

延伸阅读 CSS 动画
讲清楚了吗?
41 自定义与异步表单验证应怎样避免过期错误? 中级 偶尔 查看答案 ▾ 收起 ▴

在 Node 24 对应的浏览器基线中,setCustomValidity(nonEmptyMessage) 会让控件持续无效,直到代码明确调用 setCustomValidity('')。相关字段变化时必须清除或重新计算消息。远程检查要合理 debounce,把结果与提交值或序号关联,并忽略或中止旧响应,防止较慢的拒绝覆盖较新的有效状态;服务端验证仍是最终权威。代价是需要额外状态管理。若每次按键都发起无顺序控制的验证,会造成闪烁、请求膨胀,以及描述旧值的错误。

延伸阅读 表单验证
讲清楚了吗?
42 第一个前端项目中,HTML、CSS 与 JavaScript 各自负责什么? 初级 常见 查看答案 ▾ 收起 ▴

在 Node 24 的前端基线中,HTML 负责内容结构、原生控件、链接与表单语义;CSS 负责呈现和具有韧性的布局;JavaScript 负责平台无法单独表达的状态迁移与交互。应先做可用文档,再逐层增强,并检查解析后的 DOM,而不是只看模板缩进。代价是不能急于使用框架捷径。样式像按钮的可点击 div 仍缺少键盘和禁用行为;只为一张截图绝对定位的页面也会在缩放、长文本或窄容器下失效。

讲清楚了吗?
43 页面源码与用户看到的结果不一致时,应检查浏览器的哪些阶段? 初级 常见 查看答案 ▾ 收起 ▴

使用 Node 24 对应的浏览器工具时,应先检查解析后的 DOM,因为 HTML 解析器可能修复无效嵌套。随后查看匹配与计算后的 CSS、盒布局、绘制和合成信息,最后在可访问性树中核对公开的名称、角色与顺序;Network 和 Console 则能发现资源失败或脚本异常。每个视图回答不同问题,截图本身看不到机制。代价是诊断要分层进行;盲目修改源码可能一直对抗解析器修复、继承或缺失资源,而没有触及真实故障。

讲清楚了吗?
51 Tailwind v4 项目应怎样平衡主题 token 与任意值? 中级 常见 查看答案 ▾ 收起 ▴

在 Tailwind CSS 4.3.3 中,共享设计值应放入 @theme,形成 utility 与 variant 可复用的词汇。任意值适合真正的一次性约束,但大量重复或近似的 mt-[13px]、自定义十六进制颜色,会让评审者无法判断差异是否有意。重复值应提升为命名 token 或组件,并检查生成后的层叠;HTML 中 class 文本的先后本身不决定冲突 utility 谁胜出。代价是需要治理,但把每个试验值都塞进主题,也会像无限制任意值一样迅速污染系统。

延伸阅读 Tailwind CSS
讲清楚了吗?

布局

8个问题
06 主轴与交叉轴怎样决定 Flexbox 的对齐方式? 初级 常见 查看答案 ▾ 收起 ▴

主轴由 flex-direction 决定,不是固定的水平方向。row 跟随书写模式的行内轴,column 跟随块轴,reverse 值会交换轴的起点和终点。justify-content 在主轴上分配剩余空间,align-items 与 align-self 在垂直的交叉轴上放置项目,align-content 则在那里分配多条 Flex 行。应先确定 flex-direction、writing-mode 和 direction,再选择对齐属性,避免把 justify-content 死记成水平对齐、把 align-items 死记成垂直对齐。

讲清楚了吗?
07 为什么 Flex 项目的 flex-shrink 为 1 时仍会溢出? 中级 常见 查看答案 ▾ 收起 ▴

flex-shrink 负责分配负剩余空间,但不会覆盖项目的最小尺寸。主轴最小尺寸默认为 auto,可能得到与内容有关的下限,长且不可断的字符串或带固有尺寸的元素尤其容易触发。目标尺寸到达下限后,项目会被冻结,剩余缩减转移给其他项目;所有项目都受限时,整行只能溢出。应找到真正承载内容的项目,只在确实允许收缩时设置 min-inline-size: 0,并明确选择换行、裁剪或滚动策略。

讲清楚了吗?
08 fr 单位表示什么?为什么 1fr 轨道仍可能溢出? 中级 常见 查看答案 ▾ 收起 ▴

fr 表示网格容器中弹性剩余空间的一份,不是完整宽度的百分比。固定轨道和间隔先占用空间,弹性轨道再分配剩余部分。普通 1fr 轨道还有自动最小值,可能采用长字符串或固有尺寸子元素的最小内容贡献。设计确实允许收缩时,应对轨道使用 minmax(0, 1fr),或对项目设置 min-inline-size: 0,再明确内容应该换行、裁剪还是滚动,而不是一律隐藏溢出。

延伸阅读 CSS 网格布局
讲清楚了吗?
09 响应式 CSS 应在什么情况下使用媒体查询而不是容器查询? 中级 常见 查看答案 ▾ 收起 ▴

条件属于整体浏览环境时,应使用媒体查询,例如视口级页面结构、打印、配色方案、动态效果偏好或输入能力。可复用组件因父级分配空间而变化时,应使用容器查询。选择之前还要判断 Grid 或 Flexbox 的内在尺寸能否在没有离散切换的情况下表达约束。查询坐标系应与拥有决策的对象一致。宽视口中的窄侧栏卡片就是典型反例:此时视口查询会得到错误答案。

讲清楚了吗?
10 怎样理解 Tailwind 的响应式变体与状态变体? 中级 偶尔 查看答案 ▾ 收起 ▴

应把每个前缀转换成它生成的 CSS 条件。无前缀工具是移动优先基线,md 与 xl 从各自最小宽度起持续生效,并不代表设备类别。hover、focus-visible、disabled、dark 与 motion-reduce 添加相互独立的状态或媒体条件;堆叠变体要求所有具名条件同时成立。应测试每个断点前后各一个 CSS 像素,再分别测试键盘焦点、触摸输入、减少动态效果与颜色模式。工具类重排或隐藏内容时,还要比较 DOM、视觉与焦点顺序。

延伸阅读 Tailwind CSS
讲清楚了吗?
37 CSS Grid 怎样创建隐式轨道,它为什么会破坏响应式布局? 中级 常见 查看答案 ▾ 收起 ▴

在 CSS Grid Layout Level 2 中,grid-template-columns 与行模板定义显式网格;自动放置或定位到模板范围外的项目会创建隐式轨道,其尺寸由 grid-auto-columnsgrid-auto-rows 决定。因此,容器缩为单列后遗留的 grid-column: 2 仍可能生成意外的第二列并造成溢出。应在每种布局模式下使用网格检查器核对轨道与项目位置。自动放置很方便,但模板变化时,显式子项坐标若未在响应式规则中重置就会很脆弱。

延伸阅读 CSS 网格布局
讲清楚了吗?
38 嵌套网格何时应使用 subgrid,而不是重复定义轨道? 高级 偶尔 查看答案 ▾ 收起 ▴

在 CSS Grid Layout Level 2 中,subgrid 可让子网格在指定轴上复用父网格的轨道尺寸与网格线位置。它适合一组内容长度不同的卡片,让标题、正文和操作区跨卡片对齐;子网格仍拥有自己的 grid item,也可独立定义另一条轴。代价是组件布局与父级耦合更紧;若组件应自行决定尺寸,应使用独立嵌套网格。复制一份 repeat() 只会暂时看似对齐,父级 gap、轨道尺寸或内容约束一变就会分离。

延伸阅读 CSS 网格布局
讲清楚了吗?
46 应怎样选择并测试响应式断点? 中级 常见 查看答案 ▾ 收起 ▴

使用 Media Queries Level 5 时,应先让布局能够自然换行和收缩,再用有代表性的长内容与缩放逐步改变宽度,直到某个具体约束失效,并围绕该位置用合适的相对单位设置断点,而不是命名为“平板宽度”。测试要覆盖断点两侧、狭窄分屏、文本扩展和非鼠标输入。代价是断点由内容而非设计稿决定。宽度无法可靠推断触摸能力,未来新增设备分类也修复不了脆弱的固定布局。

讲清楚了吗?

React

7个问题
11 为什么三次 setState 调用可能只增加一次,更新函数何时能修复它? 初级 常见 查看答案 ▾ 收起 ▴

状态值是创建当前处理器那次渲染的快照;调用 setter 不会改写正在执行的快照。因此,连续三次 setCount(count + 1) 会把同一个替换值加入队列。传入 c => c + 1 则会加入纯更新函数,React 按顺序把它们应用到待处理状态,所以三次调用会增加三次。只要下一个值依赖前一个值,就应使用更新函数。它不会让彼此独立的状态更新自动具备原子性;若多个字段必须保持一致,应把它们放进同一状态对象或 reducer。

延伸阅读
讲清楚了吗?
12 useEffect 应解决什么问题,怎样的清理才算正确? 中级 常见 查看答案 ▾ 收起 ▴

useEffect 应让已提交的组件与外部系统同步,例如订阅、定时器、浏览器 API 或非 React 控件。它不是计算渲染数据或处理点击事件的默认位置。依赖列表必须包含 setup 读取的每个响应式值,使 React 能在这些值变化后重新同步。cleanup 要使用旧值撤销对应的 setup:取消同一个处理器、清除同一个定时器,或中止已经过期的请求。React 会在依赖变化后的下一次 setup 前以及组件移除后执行 cleanup,因此 setup 与 cleanup 应构成可重复执行的一对操作。

延伸阅读
讲清楚了吗?
13 为什么 React.memo 可能无法跳过子组件渲染,应如何评估修复? 中级 常见 查看答案 ▾ 收起 ▴

React.memo 默认使用 Object.is 比较每个 prop,因此父组件每次渲染时新建的对象、数组或函数,即使内容相同,标识也不同。只有当某个值跨越 memo 边界,而且性能分析证明跳过子组件确有收益时,才需要稳定其标识;把常量移出渲染过程或简化 prop 往往已经足够。自定义比较器必须比较影响输出和行为的全部 prop,包括回调,否则可能保留陈旧闭包。memo 是性能优化,不是正确性保证,最终应使用 React Profiler 验证效果。

延伸阅读
讲清楚了吗?
14 use client 边界会怎样改变 React Server Components 树? 高级 偶尔 查看答案 ▾ 收起 ▴

该指令把模块标记为客户端模块图的入口,因此这个模块及其导入的模块可以被发送到浏览器执行。它不会把上层所有 Server Component 都变成 Client Component。Server Component 可以渲染 Client Component,但作为 prop 穿过边界的值必须符合 React 支持的序列化规则;普通函数不能直接传递,除非框架把它公开为 Server Function。边界应包住尽可能小的交互子树,数据访问与密钥留在服务端,并检查生产客户端模块图,因为一次方便的 import 可能把大量代码带过边界。

延伸阅读
讲清楚了吗?
15 为什么必须把 Server Action 当作公开请求处理器? 高级 常见 查看答案 ▾ 收起 ▴

客户端可以绕过应用正常渲染的按钮或表单,直接用篡改后的参数调用生成的服务端端点。因此,Action 必须验证调用者身份,校验其对具体资源和操作的权限,解析并验证每个输入,并在写入附近执行业务不变量。TypeScript 类型与客户端验证到了网络边界都不再是安全控制。返回值只应包含客户端需要的字段,不要泄露内部错误,并明确重试语义。重新验证缓存或重定向只是写入后的界面行为,不能替代事务、幂等保护、速率限制或需要的 CSRF 防护。

延伸阅读
讲清楚了吗?
39 为什么实时变化的值通常更适合使用 CSS 自定义属性,而不是生成 class? 中级 常见 查看答案 ▾ 收起 ▴

在 React 19 的 CSS-in-JS 系统中,size、tone 等有限变体可以映射到稳定的提取或缓存 class。鼠标坐标、进度和任意用户颜色可能每帧变化;把每个值插值进规则会不断生成近似 class,并重复插入样式。应保持结构规则稳定,只通过命名明确的 CSS 自定义属性传递实时标量。代价是在 DOM 边界出现一个内联值,但样式表仍可复用,浏览器也能更新数值而无需持续创建新的选择器身份。

延伸阅读 CSS-in-JS
讲清楚了吗?
40 CSS-in-JS 系统在服务端渲染与 hydration 期间必须保证什么? 高级 常见 查看答案 ▾ 收起 ▴

在 React 19 中,服务端必须收集渲染树使用的全部规则,在对应标记可见前输出,并保证服务端与客户端生成相同且确定的 class 标识与插入顺序。客户端 hydration 时应复用服务端样式表,而不是再次插入。应测试流式边界、条件渲染、多请求隔离与纯客户端导航。代价是需要针对框架做集成和提取。进程级可变样式表可能把一个用户的样式泄漏到另一个响应,而不确定的哈希会造成闪烁和 hydration 不匹配。

延伸阅读 CSS-in-JS
讲清楚了吗?

Vue

5个问题
16 Vue 如何知道哪些响应式更新应重新运行 effect? 中级 常见 查看答案 ▾ 收起 ▴

Vue 在运行时跟踪依赖。当 effect、computed getter 或组件渲染正在执行时,通过响应式 Proxy 读取属性,会记录该属性与当前 effect 的关系。之后通过 Proxy 写入受影响的键,才会触发为该键登记的 effect。因此,直接修改原始对象不会通知 Proxy 的使用者,未被执行分支中的属性也还不是依赖。调试时应追踪准确的读取与写入路径,不要假设整个对象都被监听;需要跟踪的响应式读取必须发生在预期的执行过程内。

延伸阅读
讲清楚了吗?
17 在 Vue 中怎样选择 ref 与 reactive? 初级 常见 查看答案 ▾ 收起 ▴

状态是基本类型、可能整体替换,或需要在 composable 之间传递稳定的响应式包装时,应使用 ref。在 JavaScript 中通过 .value 读写,模板通常会自动解包。reactive 返回对象的 Proxy,适合调用方持续修改稳定对象结构的情况。把变量替换成新的原始对象,会让使用旧 Proxy 的消费者失去联系;直接解构基本类型属性,也会绕过负责跟踪的 Proxy 访问。解构后的属性仍需保持关联时可使用 toRefs,同时不要把原始对象与 Proxy 混作标识键。

延伸阅读
讲清楚了吗?
18 Vue 的派生状态何时应使用 computed 而不是 watch? 初级 常见 查看答案 ▾ 收起 ▴

如果一个值能由其他响应式状态纯粹推导出来,应使用 computed。Vue 会跟踪 getter 的依赖、缓存结果,并在依赖失效后重新计算。只有变化必须触发请求、持久化、日志或命令式 API 调用等副作用时,才使用 watch,并明确指定数据源。用 watch 把一个响应式值复制到另一个值,会制造两个事实来源,引入额外的时序问题和循环风险。例如,筛选后的商品列表应由 computed 返回;把所选筛选条件保存到存储则适合 watch。

延伸阅读
讲清楚了吗?
19 怎样防止 Vue watcher 中的异步任务写入陈旧结果? 高级 偶尔 查看答案 ▾ 收起 ▴

每次 watcher 执行时都应登记失效清理,为本轮请求创建 AbortController,并在被监听的数据变化而请求尚未完成时中止它。结果处理器还应只提交与当前数据源对应的响应。使用 onWatcherCleanup 时,必须在回调的同步阶段、任何 await 之前完成登记;回调参数提供的 onCleanup 也是可用方式。在 setup 中同步创建的 watcher 会绑定组件卸载,而稍后在定时器中创建的 watcher 不会以同样方式自动归属组件,需要显式停止。

延伸阅读
讲清楚了吗?
20 为什么 Nuxt 初始数据应使用 useFetch 或 useAsyncData,而不是在 setup 中直接调用 $fetch? 中级 偶尔 查看答案 ▾ 收起 ▴

在同构渲染中,setup 会先在服务端运行以生成 HTML,又会在浏览器 hydration 时运行。若在 setup 中直接调用 $fetch,请求可能重复,而且两次渲染可能得到不同数据。useFetch 与 useAsyncData 会用带键状态协调服务端请求,把结果序列化进 Nuxt payload,并让客户端在 hydration 时复用。$fetch 更适合表单提交等事件驱动请求,不适合初始 SSR 状态。还要保持 key 与选项一致,处理 pending 和 error,并避免把敏感或不必要的大量数据放入客户端 payload。

延伸阅读
讲清楚了吗?

性能

5个问题
21 真实用户数据与实验室轨迹在前端性能工作中怎样分工? 中级 常见 查看答案 ▾ 收起 ▴

真实用户数据反映不同设备、网络、路由、缓存与交互下的实际体验;分析时应按有意义的群体拆分,并观察分布而不是单一平均值。实验室测试提供可控、可重复的轨迹,用于复现较慢群体,并把耗时归因到网络、脚本、渲染或布局。两者不能互相替代:快速的本地轨迹可能遗漏弱设备,较差的真实指标本身也无法指出责任代码。应从用户可见的回归出发,在有代表性的约束下复现,只改变一个瓶颈,再同时验证轨迹与真实趋势。

延伸阅读
讲清楚了吗?
22 代码分割边界应放在哪里,哪些因素会让分割反而更慢? 中级 常见 查看答案 ▾ 收起 ▴

边界应包住体积较大、可独立到达且首个有用视图不需要的代码,例如路由或可选编辑器。dynamic import 会创建异步依赖边界,但每个 chunk 都增加发现、请求、调度、解析与失败处理成本。chunk 过小、配置导致共享依赖重复,或 fallback 引发布局偏移,都可能抵消收益。应测量首屏字节与执行时间、后续导航延迟、缓存复用和请求失败行为。只预取用户很可能访问的下一路径,并让加载与错误状态真正可用,而不是只用 spinner 掩盖等待。

延伸阅读
讲清楚了吗?
23 srcset 与 sizes 如何帮助浏览器选择图片资源? 初级 常见 查看答案 ▾ 收起 ▴

使用宽度描述符时,srcset 列出可选文件及其固有宽度,sizes 则描述页面不同媒体条件下的图片槽位宽度。浏览器会把这个槽位估算与设备像素比等因素结合,在完整布局确定前选择合适候选。因此,即使 CSS 最终把图片显示得很小,错误的 sizes 仍可能下载过大的资源。只有图片来源或裁剪内容需要变化时才使用 picture,单纯分辨率切换不需要。还应保留 src 回退,提供固有 width 与 height 预留空间,并在代表性视口宽度和像素密度下检查实际请求。

延伸阅读
讲清楚了吗?
24 在部分 hydration 页面中,怎样的 island 边界才合理? 高级 偶尔 查看答案 ▾ 收起 ▴

合理的 island 应包含一段完整交互,以及必须在浏览器运行的最小状态;周围内容仍是可用的服务端 HTML。边界并非免费:每个 island 都可能增加入口、运行时代码、序列化、调度与协调成本。若两个控件持续共享状态,把它们拆开可能比一起 hydration 更昂贵。加载触发方式应由用户需求决定,例如立即、可见、空闲或交互时加载,并在 JavaScript 到达前保留可用回退。还要测试键盘操作、状态交接、慢速加载和单个 island 失败,再与更粗边界比较传输和执行的 JavaScript。

延伸阅读
讲清楚了吗?
25 流式 SSR 响应一旦开始发送,会出现什么关键权衡? 高级 少见 查看答案 ▾ 收起 ▴

流式渲染可以在慢内容就绪前先发送可用 shell 与 Suspense fallback,改善渐进显示,但不会让底层工作消失。响应头和字节一旦提交,服务器就无法再按通常方式修改 HTTP 状态。因此,关键权限判断、重定向与 shell 级失败必须在开始流式发送前解决;之后的边界失败需要流内或客户端恢复路径,并在服务端记录。边界应对应有意义的加载状态,还要中止已放弃的渲染、遵守流背压,并测量首批内容、完成时间和 hydration。首字节更快本身不能证明体验更好。

延伸阅读
讲清楚了吗?

无障碍

8个问题
26 减少动态效果的实现应保证什么? 中级 常见 查看答案 ▾ 收起 ▴

实现应移除或替换非必要运动,同时保留内容、状态反馈、焦点顺序和任务完成路径。应使用 prefers-reduced-motion 为每种效果选择有意设计的替代方案,不能假设一个全局近零时长重置就安全。JavaScript 不应依赖 transitionend 或 animationend 才提交状态,因为被禁用或未生成的效果可能没有可用的结束事件。两种媒体设置都要测试,还要覆盖快速重复输入,并确认旋转或入场运动不是传达重要信息的唯一方式。

延伸阅读 CSS 动画
讲清楚了吗?
27 order 与反向 Flex 方向有什么无障碍风险? 中级 偶尔 查看答案 ▾ 收起 ▴

它们会在视觉上重排 Flex 项目,却不会改写 DOM。非视觉呈现的阅读顺序和顺序键盘焦点通常仍按源顺序进行,因此用户可能看到控件从左到右排列,按 Tab 键时却沿另一顺序移动。最安全的修复是让源顺序符合内容与任务逻辑,再在每个断点采用保留该顺序的布局。只应对装饰性或语义互不依赖的项目做视觉重排,并用键盘导航、屏幕阅读器、两种文字方向和无样式视图验证结果。

讲清楚了吗?
28 怎样让表单验证反馈具备无障碍性? 中级 常见 查看答案 ▾ 收起 ▴

每个控件都需要可见标签,格式要求也应在用户出错前就能发现。验证失败时,应提供简洁文字,说明问题及修复方式,通过 aria-describedby 把消息与控件关联,并在控件上设置 aria-invalid。对于长表单,应增加错误摘要,让其中的链接聚焦对应控件,再在提交失败后按可预测方式移动焦点。不要只依赖颜色、占位符,也不要在用户输入时反复触发实时区域通知。最后要用键盘和屏幕阅读器测试失败、修正与重新提交,并覆盖动态字段和服务器返回的错误。

延伸阅读 表单验证
讲清楚了吗?
29 为什么应该先选择原生 HTML 元素,而不是给通用元素添加 ARIA 角色? 初级 常见 查看答案 ▾ 收起 ▴

应先选择内置契约符合任务的元素。按钮已经具备角色、顺序焦点、键盘激活、禁用状态、表单行为,以及适应平台模式的浏览器样式。给 div 添加 role=button 只会改变公开角色,不会实现这些行为。只有原生 HTML 无法表达名称、状态或关系,并且 ARIA in HTML 允许时,才补充 ARIA。最后还要在真实浏览器中验证计算名称与角色、键盘路径、焦点可见性和状态变化。

讲清楚了吗?
30 怎样验证 AI 生成页面的无障碍性? 高级 常见 查看答案 ▾ 收起 ▴

应先检查解析后的 DOM,而不是截图或模板缩进,因为 HTML 解析器可能修正无效嵌套。列出标题、地标、表单与交互元素,再到可访问性树中检查计算名称、角色和状态。随后只用键盘操作跳过链接、导航、披露控件、对话框与表单提交,同时检查焦点顺序和可见性。自动规则能发现重复 ID、名称缺失和无效 ARIA,却无法判断标签与阅读顺序是否符合任务。最后要用屏幕阅读器走查关键路径,并把可重复检查保留为回归测试。

延伸阅读
讲清楚了吗?
44 渐进增强在小型前端中保护了什么? 中级 偶尔 查看答案 ▾ 收起 ▴

在 Node 24 的前端基线中,链接应保留 href,表单应先具备 action、method、label 与服务端验证,再由 JavaScript 增加快速导航或行内反馈。这样在加载缓慢、脚本失败、辅助技术使用和直接请求时,核心任务仍可完成。不可信文本应使用 textContent 插入,而不是 innerHTML;渐进增强不会放松 XSS 边界。代价是要同时维护基础路径与更丰富交互,但若 JavaScript 是唯一入口,一个 bundle 或运行时错误就会让整个任务不可用。

讲清楚了吗?
45 当分节元素不会自动生成大纲时,应怎样选择标题级别? 初级 偶尔 查看答案 ▾ 收起 ▴

按 HTML Living Standard,sectionarticle 等分节元素不会让主流浏览器自动公开嵌套标题大纲。应依据文档真实层级选择 h1h6,确保移除 CSS 后顺序仍易理解,不能把每个嵌套 section 都重置为 h1。section 通常应有明确主题与标题;纯布局容器继续用 div 即可。代价是组件组合时要维护标题级别,但字号只是视觉表现,CSS 可以把任意正确级别设计成所需样式。

讲清楚了吗?
47 为什么响应式重排必须保留有意义的源顺序? 高级 偶尔 查看答案 ▾ 收起 ▴

在 Media Queries Level 5 与 CSS Containment Level 3 下,Flex order、网格坐标和 dense packing 可以改变视觉位置,却不会同步改变 DOM 阅读顺序或顺序焦点。内容与控件应先按任务逻辑排列源代码,再构建保持该顺序的宽窄布局。容器查询可以响应组件可用的 inline size,但并不允许改变语义顺序。代价可能是构图不那么夸张。应检查键盘、屏幕阅读器、无样式视图和边界两侧行为,因为截图无法暴露顺序错位。

讲清楚了吗?

构建工具

8个问题
31 为什么 Vite 应用除了开发服务器外,还必须测试生产构建? 初级 常见 查看答案 ▾ 收起 ▴

开发服务器按需提供并转换模块,以获得快速反馈;vite build 则生成用于部署的优化依赖图,其中包含输出 chunk、资源 URL、环境变量替换和配置的浏览器目标。两者走不同执行路径,因此开发环境成功不能证明生产环境的解析、base 路径、懒加载 chunk 或服务端行为正确。应运行真实构建,并在接近生产的环境中提供其输出,测试直接导航、dynamic import、CSS 与 public 资源、环境变量和支持的浏览器。项目依赖 TypeScript 时,还要单独执行类型检查,因为转换过程本身不等于完整类型检查。

延伸阅读
讲清楚了吗?
32 Webpack loader 与 plugin 有什么区别? 初级 常见 查看答案 ▾ 收起 ▴

loader 在 Webpack 构建依赖图时转换匹配的模块资源。rule 负责选择文件,loader 链则把转换后的内容与元数据依次传递。plugin 接入更广泛的 compiler 与 compilation 生命周期,因此能在整个依赖图范围协调资源生成、优化、环境注入或报告等任务。若任务本质是“把这个被导入的资源变成模块”,应使用 loader;若需要编译级上下文,或要生成和修改资源,则应使用 plugin。调试时,要把 rule 匹配与 loader 顺序同 plugin hook 时机分开验证。

延伸阅读
讲清楚了吗?
33 怎样验证从 Webpack 迁移到 Rspack? 中级 偶尔 查看答案 ▾ 收起 ▴

应把与 Webpack 兼容的配置视为迁移辅助,而不是行为完全一致的证明。先盘点入口、解析别名、loader、plugin、开发服务器行为、缓存设置、public path,以及部署或其他包依赖的全部输出。首先迁移一个有代表性的生产目标,并针对每个扩展检查 Rspack 当前兼容性文档。比较干净构建与缓存构建的输出文件、source map、CSS 顺序、动态 chunk、运行时行为和警告,再在受支持的 Node 版本上测试 HMR 与 CI。正确性确认后才做基准测试,并保证冷热运行使用相同机器、输入和缓存策略。

延伸阅读
讲清楚了吗?
34 现有应用采用 Turbopack 前需要哪些证据? 高级 少见 查看答案 ▾ 收起 ▴

必须证明真实应用依赖图受支持,而不能只证明脚手架项目能运行。列出自定义 Webpack 配置、loader、plugin、模块格式、CSS 行为、别名、monorepo 边界和生产部署要求,再逐项映射到 Turbopack 当前支持情况。测试开发启动、代表性依赖路径上的修改、HMR 状态保留、错误恢复、干净的生产构建和运行时 chunk 加载。应先比较正确性,再比较速度,并为缓慢或内存占用高的场景收集 trace。在 CI、预览环境与生产监控证明用户依赖的路由行为等价之前,要保留有文档的回退路径。

延伸阅读
讲清楚了吗?
35 怎样让 monorepo 构建缓存不仅快,而且正确? 高级 偶尔 查看答案 ▾ 收起 ▴

只有缓存键能够表示影响声明输出的全部输入时,缓存任务才是正确的。这些输入包括源文件、依赖版本与 lockfile 状态、配置、工具版本、相关环境变量、命令参数,以及上游任务输出。漏掉输入会得到很快但陈旧的命中;加入时间戳或宽泛的无关目录则会破坏复用。应明确任务边界与输出,规范执行环境,并把密钥与可缓存制品分开。还要通过干净构建和有意修改输入来验证,在空工作区中恢复结果,并在工具允许时使用内容哈希而不是修改时间。

延伸阅读
讲清楚了吗?
48 Sass 的 @use 与模块配置和旧式 @import 有什么区别? 中级 常见 查看答案 ▾ 收起 ▴

在 Dart Sass 1.104.0 中,@use 只加载模块一次,并通过 namespace 访问其公开成员;@forward 决定库入口向外暴露什么。带 !default 的变量应在首次加载时用 with (...) 配置,后续加载会复用同一模块,不能悄悄重新配置。旧式 @import 与全局内置函数已弃用,还会造成全局名称冲突和重复输出。代价是 namespace 与加载顺序更显式。隐藏的传递加载可能让后续配置失败,因此配置应集中在清楚的入口。

延伸阅读 Sass
讲清楚了吗?
49 怎样发现会膨胀为高成本 CSS 的 Sass 源码? 高级 偶尔 查看答案 ▾ 收起 ▴

Dart Sass 1.104.0 会在每个 include 位置展开 mixin,把循环的每次迭代编译成规则,并将嵌套选择器展开为更长的选择器链。因此很短的 SCSS 也可能生成体积大、优先级高的 CSS。应构建真实入口,检查输出的选择器与声明,比较压缩制品大小,并在代表性页面测试层叠。确有复用时优先考虑 placeholder、共享 class 或有界 map。代价是局部抽象不那么方便;只审查源码行数会漏掉重复输出和难以覆盖的嵌套。

延伸阅读 Sass
讲清楚了吗?
50 为什么 Tailwind utility 候选必须以完整文本出现在源码中? 初级 常见 查看答案 ▾ 收起 ▴

Tailwind CSS 4.3.3 会把源文件当作文本扫描,只为识别出的完整候选生成静态 CSS;它不会执行 bg-${tone}-600 之类的 JavaScript 模板字符串。应把每个允许的 tone 映射为完整字面 class;若 class 来自外部内容,则声明边界明确的 source。必须验证生产构建,因为开发文件可能意外提供候选。代价是运行时组合不再任意。过宽的 safelist 会膨胀 CSS,而动态拼接的 class 可能在一个环境可用,部署制品中却消失。

延伸阅读 Tailwind CSS
讲清楚了吗?