这已经是第六套HTML5测验题了。前五套我都出得很“温柔”重点放在标签记忆、属性对照和API名词上读者反馈也相当统一看了答案觉得全会一关页面就忘进了真实项目还是靠CtrlC、CtrlV。所以这一套我决定换个玩法不再考“某个元素是行内还是块级”这种背诵题而是把日常开发里最高频的几类场景直接变成题目让答题的人站在一个真实需求里去判断、去改代码、去解释选择。整套卷一共10题每题10分范围覆盖语义化、表单、音视频、Canvas动画、本地存储、Worker和历史路由。评分不看你能不能默写规范而看你会不会在乱七八糟的页面上做出干净、兼容、可维护的HTML5实现。适合刚学完HTML5想验证实战能力的同学也适合带新人、做面试摸底时直接拿来用。如果你去招聘网站搜“html5网页设计”岗位描述通常写得很泛会写页面、懂适配、了解前端框架。但真正接手项目后你会发现难点从来不是某个标签怎么写而是“为什么我的video在这台手机上不显示”“为什么动画在Retina屏上糊成一团”“为什么用户填了一半的表单刷新后全没了”。这套卷子就是把这类隐藏需求摊到台面上让你不用踩坑也能知道坑在哪。1. 这套“测验六”到底在测什么从背标签到扛项目1.1 为什么要换掉选择题前五套题里我特别喜欢出“以下哪个标签是HTML5新增的”“video标签的哪个属性用于自动播放”这类题。它们是合格的入门训练但也是典型的“低质量自测”哪怕你把规范背得滚瓜烂熟也不代表你能独立完成一个响应式页面更不代表你能处理浏览器兼容。搞开发的人都清楚真正磨人的往往不是知识本身而是知识的边界。比如大家都知道localStorage能存数据可很少有人会在项目里给setItem包一层try/catch直到在Safari隐私模式下被异常拍了一脸。这套“测验六”就是冲着这个目标去的。每一题都给场景、给残缺代码、给限制条件答题人必须像平时改需求一样做取舍。它不追求名词解释的精确度反而更在意“你有没有意识到这里需要做降级方案”“你会不会主动处理异常”“你能不能解释清楚为什么这样选”。选择题可以做对但换一个人来问为什么就卡壳实战题不一样要完整回答就必须把原理和场景串起来。1.2 题型分布与判分方式整套卷共10道题每题10分题号用T1到T10表示分布在四个大主题里。题号考察点对应章节T1语义化改错把div堆出来的落地页改成HTML5骨架第2章T2标题层级、main标签和无障碍设计第2章T3表单控件与原生校验移动端输入体验第3章T4不同浏览器对HTML5播放器的支持video标签写法第3章T5自动播放策略与播放器降级方案第3章T6Canvas实现爱心粒子/飘雪一类动画特效第4章T7动画性能、Retina适配与销毁逻辑第4章T8localStorage、sessionStorage、IndexedDB选型第5章T9Web Worker处理大量数据避免主线程卡死第5章T10History API实现单页切换和进度恢复第5章判分很简单60分及格说明你能处理常规HTML5页面80分算优秀说明你不仅会写还知道为什么这么写。做题的时候别翻资料不会就先跳过最后统一对答案。这比对着文档抄一遍有效得多。2. 语义化与页面骨架一栋只有div的“毛坯房”怎么翻新2.1 T1 实战改错把活动落地页改成HTML5语义结构题目直接给一段“典型老项目代码”看起来能正常显示实际上一眼望去全是语义化垃圾。div classheader div classlogoXX嘉年华/div div classnav span首页/span span赛程/span span报名/span /div /div div classcontent div classtitle活动介绍/div div classtext 这是一段活动介绍文字里面包含日期和联系邮箱。 /div div classlist div classitem赛程一/div div classitem赛程二/div /div /div div classfooter div版权所有 © 2025/div /div要求在不改变视觉效果的前提下改写成符合HTML5语义的页面骨架并说明每个改动的理由。这道题的理想答案不是把所有div机械地换成section而是先画出页面的“区块地图”顶部导航、主体内容、底部信息。有了这个地图结构就清晰了。header classheader div classlogoXX嘉年华/div nav classnav a href/首页/a a href/schedule赛程/a a href/signup报名/a /nav /header main classcontent h1活动介绍/h1 p这是一段活动介绍文字里面包含日期和联系邮箱。/p ul classlist li classitem赛程一/li li classitem赛程二/li /ul /main footer classfooter p版权所有 © 2025/p /footer踩分点有三个。第一nav必须放导航链接不能继续用span当假按钮导航里的“首页、赛程、报名”都是页面跳转用a标签不仅在语义上正确还能免费获得键盘可访问性。第二页面最核心的标题要用h1而不是“classtitle”的div。第三main标签在一个页面中只能使用一次而且别把它嵌套在header、footer、nav或article里面。很多人在这一步会继续犯一个错误看到内容区域就套section却没有给section加标题。规范的section应该包含一个标题h1到h6都可以如果一个区块不需要标题那它大概率只是普通div。2.2 T2 补充问答标题层级、main与可访问性第二题是一个补充问答题这个页面的h1到h6应该怎么安排为什么不能随便跳级我见过太多页面在h1后面直接跟h3理由是“h3的字号正好符合设计稿”。这种操作非常典型也是面试官最爱追问的细节。正确做法是标题层级像目录一样逐级下降h1是整个页面或站点最顶层主题h2是页面内的大区块h3是大区块下面的子标题。你当然可以用CSS把h3的字号改得比h2大但语义层级不变。屏幕阅读器用户通常会用标题快捷键在页面里跳转如果层级混乱等于给他们的导航地图画错了路线。这道题还应该答出main无障碍属性。HTML5规范里main本身已经表示“文档主要内容”但兼容性兜底时很多人会加rolemain这是可接受的。另一个容易被忽略的是nav的aria-label当页面里存在多个导航区域时没有标签的nav会让辅助技术用户分不清是哪个导航。现在很多“html5网页设计”岗位要求里都写了“懂无障碍”其实基础就是这些细节。3. 表单与音视频一到真机就原形毕露的交互题3.1 T3 报名表单HTML5控件的正确姿势第三题是一个活动报名表单需求描述如下需要收集姓名、手机号、邮箱、出生日期、身份证号和参赛组别组别可以从下拉列表里选参赛须知要给一个默认勾选的同意复选框。要求使用HTML5表单特性实现并考虑移动端输入体验。先说基础答案。姓名用input typetext手机号用input typetel邮箱用input typeemail出生日期用input typedate身份证号用input typetext加pattern参赛组别用select加option同意条款用input typecheckbox。每个必填项加required邮箱和手机号这一类有格式的输入还应该配合autocomplete属性方便移动端联想。很多人的答案到这里就停了但真正拿高分的人会继续往下说typetel在移动端会弹电话键盘但并不意味着它会做格式校验所以手机号依然需要pattern。身份证号长度固定18位加minlength18 maxlength18只是基础还要用pattern限制字符类型。input typedate在桌面端和iOS端样式不统一如果你很在意视觉愿意做自定义日期选择器也要保留一个可访问的隐藏原生输入框做兜底否则表单会变成只能看不能填的摆设。移动端体验还藏着一个容易忽略的属性inputmode。纯数字输入除了typenumber更推荐inputmodenumeric加pattern[0-9]*这样在部分浏览器里既能弹出数字键盘又不会触发number输入框自带的步进按钮和千分位行为。另外一个细节是enterkeyhintdone它可以把键盘右下角的按钮文案改成“完成”这个小属性在填完手机号切下一项时体验提升非常明显。3.2 T4 多浏览器视频播放器支持一份必须写对的video标签第四题直接命中热搜词“不同浏览器对html5播放器的支持”。题目是在线教育平台需要一个视频播放器要覆盖Windows上的Chrome、Edge、Firefox还要覆盖iPhone和Android微信内置浏览器。请写出完整的video标签并说明需要准备哪些视频格式。大部分人的第一版答案是video srccourse.mp4 controls/video这版在Chrome上很完美到了Firefox可能能播但在Safari上要看编码在Android WebView里更是不稳定。要做一个基础兼容方案至少应该写成video controls playsinline muted preloadmetadata postercover.jpg source srccourse.mp4 typevideo/mp4 source srccourse.webm typevideo/webm 你的浏览器不支持HTML5视频请升级浏览器。 /video要解释清楚为什么准备两种格式。H.264/AAC的MP4是当前兼容性最好的底座绝大多数浏览器和移动端都认识WebM/VP9在Chrome、Firefox、Edge上表现很好而且文件体积经常更小。source标签会按顺序试探第一个能播就停止所以MP4放前面WebM放后面最后再留一段纯文本降级。playsinline这个属性太重要了。iPhone上的Safari和微信浏览器如果不加它视频会被强制全屏播放用户点开视频直接跳出页面体验极其糟糕。muted则和自动播放策略有关即使在代码里写了autoplay带声音的视频也很难在移动端自动播起来加了muted后成功率会高很多。preloadmetadata的意思是页面加载时只拉取视频元数据而不是整段下载对长视频页面来说能省不少流量。这道题还有一个加分点别迷信“支持HTML5视频”这句话。Safari对MP4内部编码也有要求某些老安卓设备对H.264 High Profile支持不好所以正式项目的视频编码档位、分辨率、码率都需要在测试机列表里过一遍。真机测试列表里一定要有iPhone旧机型、Android中低端机和微信内置浏览器三者的表现经常完全不一样。3.3 T5 自动播放与播放策略为什么页面没有声音第五题是T4的延伸给了一段带autoplay的视频却无法自动播放要求分析原因并给出至少三种解决思路。首先明确浏览器策略现代浏览器普遍限制带声音的自动播放Chrome桌面版要求用户先与页面产生交互Safari的智能防跟踪策略更严格。页面一加载就直接autoplay且不带muted的视频大概率会被浏览器拦下来。这不是你的代码写错了而是浏览器在保护用户。解决方案有三条路。第一视频默认静音自动播放页面里放一个声音开关用户点击后通过video.muted false开启声音。第二监听用户的首次点击事件在回调里调用video.play()因为用户已经与页面交互这个播放请求通常会被放行。第三把自动播放当成渐进增强先用poster显示封面用户点击封面再播放这样既稳妥又尊重用户选择。这道题真正想考察的是“你愿不愿意面对浏览器限制做产品方案”。很多开发者的第一反应是搜“如何绕过自动播放限制”但绕过从来不是正路。正规项目中产品要的是一个“看起来能留住用户”的视频区而不是必须出声的画面。4. Canvas与动画特效圣诞贺卡和爱心烟花背后的性能底线4.1 T6 实现一个爱心粒子动画第六题是一道代码题标题里带了热搜词“html5爱心烟花特效代码”和“html5圣诞贺卡”的味道。题目要求用Canvas实现一个爱心粒子飘落效果类似圣诞贺卡里飘雪、爱心烟花绽放后粒子散落的视觉效果。给出核心代码并解释实现思路。一个合格的答案长这样canvas idheartCanvas/canvas script const canvas document.getElementById(heartCanvas); const ctx canvas.getContext(2d); const particles []; let raf null; let last 0; function resize() { const dpr window.devicePixelRatio || 1; const rect canvas.getBoundingClientRect(); canvas.width rect.width * dpr; canvas.height rect.height * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } function createHeartPoint(scale 1) { const t Math.random() * Math.PI * 2; const x 16 * Math.pow(Math.sin(t), 3); const y 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t); return { x: x * scale, y: -y * scale }; } function spawn(count) { for (let i 0; i count; i) { const p createHeartPoint(0.6 Math.random() * 0.8); particles.push({ x: canvas.width / 2 p.x, y: canvas.height / 2 p.y, vx: (Math.random() - 0.5) * 0.3, vy: 0.5 Math.random() * 0.8, alpha: 1, size: 2 Math.random() * 3, life: 1 }); } } function tick(time) { const dt Math.min((time - last) / 16.667, 3); last time; ctx.clearRect(0, 0, canvas.width, canvas.height); for (let i particles.length - 1; i 0; i--) { const p particles[i]; p.x p.vx * dt; p.y p.vy * dt; p.life - 0.004 * dt; if (p.life 0) { particles.splice(i, 1); continue; } ctx.globalAlpha Math.max(p.life, 0); ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); ctx.fill(); } raf requestAnimationFrame(tick); } resize(); spawn(120); raf requestAnimationFrame(tick); window.addEventListener(resize, resize); /script解释部分要讲清楚两个关键点。第一爱心点的生成不是随机打点而是用参数方程x 16sin³t、y 13cost - 5cos2t - 2cos3t - cos4t生成落在心形曲线上的一系列点然后给它们加一点随机速度让粒子散开并下落。第二动画循环用requestAnimationFrame通过时间差dt计算每帧位移这样刷新率不同的设备上粒子速度基本一致。直接每一帧都加固定像素是最典型的错误60Hz和120Hz屏幕上速度会差一倍。4.2 T7 高分追加题性能、Retina、暂停与销毁第七题是T6的追问这段动画在手机上有哪些性能隐患如果页面切到后台动画还继续跑吗跳转页面时怎么彻底释放第一个隐患是Retina屏模糊。默认canvas.width等于CSS像素宽度没有乘devicePixelRatio在iPhone上画出来的粒子边缘会发虚。解决办法就是resize函数里做的把画布的实际分辨率乘以dpr同时用ctx.setTransform把逻辑坐标系拉回来。这个适配现在几乎是Canvas项目的标配不做等于没做完。第二个隐患是对象管理和每帧重复计算。粒子数量要设置上限不能无限spawn最好维护一个“粒子池”而不是每帧push新对象、splice旧对象。粒子少的时候无所谓一旦数量上几千频繁创建和删除对象就会触发垃圾回收表现就是动画一顿一顿的。静态背景比如贺卡边框、底部文字应该先画到离屏Canvas上每帧直接drawImage贴回去而不是反复执行一堆复杂绘图指令。第三个隐患是生命周期。页面隐藏时requestAnimationFrame会自动暂停一部分浏览器但不如主动监听可靠。建议做两件事通过visibilitychange事件暂停动画退出页面或组件卸载时调用destroy函数取消动画帧、移除事件监听器。很多踩坑都是从“页面跳走再回来动画还在跑”开始的浪费电不说还会造成内存泄漏。封装的时候可以暴露一个简单的接口const heartRain createHeartRain(canvas, { count: 200, color: #ff6699 }); heartRain.start(); heartRain.destroy();这样无论是路由切换还是用户点按钮关闭特效都能干净利落地释放资源。5. 本地存储、Worker与路由让页面具备“客户端应用”的能力5.1 T8 草稿箱场景localStorage、sessionStorage还是IndexedDB第八题是个很常见的产品需求用户填写一个比较长的测验问卷填了一半关掉浏览器几个小时后再打开希望上次填的内容还在。要求选择客户端存储方案并给出理由。这题的答案不能只写“用localStorage”就完了。localStorage适合小规模键值对存储上限大约5MBAPI是同步的读写简单。问卷草稿如果只有几十个字段用它完全没有问题。但你要意识到它的边界只能存字符串存对象要JSON.stringify存储空间满会抛异常Safari隐私模式下写入可能直接失败。所以任何存储操作都得包try/catch。sessionStorage的语义是“一个标签页的生命周期”关掉标签页数据就没了这个场景天然不合适。IndexedDB才是真正面向结构化数据和更大容量的方案适合存题库、答题记录、图片音频等资源。它的API是异步的使用起来更重但如果答案只说“我选IndexedDB因为它更强”同样会被扣分因为这属于杀鸡用牛刀。一个正经答案应该先分析数据量再给方案。存储选型还有一个关键点写数据不要太频繁。用户每打一个字就setItem一次虽然也能用但没必要。可以在输入事件里做防抖比如停止输入500毫秒后再保存或者用pagehide、visibilitychange这类时机做最后保存这样既不会丢失数据也不会把页面拖慢。5.2 T9 十万条数据统计为什么页面卡死怎么救第九题是一道性能题。页面上有个按钮点击后要对10万条数字做统计排序结果点击后页面彻底卡住旋转的加载动画也停了。要求说出原因并用代码给出解决方案。原因很简单10万条数据的排序和遍历在主线程上执行阻塞了渲染。浏览器是单线程的JS脚本执行期间无法绘制页面所以加载动画停转。解决方案是Web Worker。把数据传给Worker在Worker线程里排序计算完成后再把结果传回主线程更新界面。// main.js const worker new Worker(sort-worker.js); worker.onmessage (e) { document.getElementById(result).textContent e.data; }; worker.postMessage(bigArray); // sort-worker.js self.onmessage (e) { const data e.data; data.sort((a, b) a - b); self.postMessage(data); };但完整答案一定要补充Worker的边界Worker里没有window和document不能操作DOM不能直接访问localStorage至少不是所有浏览器都支持通信靠postMessage数据传递有结构化克隆的开销。如果数据是大量数字用ArrayBuffer配合transfer参数做转移可以避免复制代价是主线程里的原数据会失效。这道题要是能答出“Worker适合CPU密集任务但不适合所有场景”就进入了实战那一档。5.3 T10 单页切换与测验进度恢复History API怎么用才不踩坑第十题继续沿用测验场景希望点击页面底部“上一题/下一题”时URL从/quiz/1变成/quiz/2不刷新页面并且刷新后能回到当前题目按浏览器后退键也能正确返回上一题。问怎么实现。主流方案是HTML5 History API。核心操作是history.pushState(state, , url)它会把新状态压入历史栈同时改变地址栏URL但不会触发页面刷新。需要监听popstate事件处理用户点后退或前进的动作注意pushState本身不会触发popstate。function goToQuestion(id) { history.pushState({ page: id }, , /quiz/${id}); renderQuestion(id); } window.addEventListener(popstate, () { const state history.state; renderQuestion(state ? state.page : 1); });这里至少有三个坑必须提到。第一刷新/quiz/2时需要后端或静态服务器把请求回退到入口页并交给前端路由处理否则直接404。第二移动端浏览器在后退时会触发pageshow或visibilitychange如果和popstate组合使用容易让页面状态被重复初始化所以跳转逻辑要加一个“防抖锁”。第三history.state能存状态对象但别把大对象往里塞它只能存可结构化克隆的数据存题目详情这种大对象很容易超出浏览器限制。至于hash路由和History API的区别也要一点hash模式兼容性更好不需要服务器配置但URL会带丑陋的#号且无法参与服务端SEOHistory API更干净前提是服务器要配合。现在新项目里History API是主流但遇到一些老旧WebView时hash仍然是最稳的兜底方案。6. 答案要点与易错点复盘做完这套题我对HTML5项目的新认知6.1 各题踩分点速查整套卷做完之后可以直接对照这个表快速评估自己哪里丢分题号必须答出的点容易丢分的位置T1用header、nav、main、footer重构导航用a标签把section当div乱用不给标题T2标题层级不跳级main页面唯一只考虑字号不考虑语义T3合适type、required、pattern、autocomplete、inputmode忽略移动端键盘和真机校验差异T4MP4WebM多sourceplaysinline兜底合理preload只写一个src忽视SafariT5muted自动播放用户交互后开声音poster降级试图绕过浏览器策略T6心形参数方程、rAF、dt时间差、clearRect每帧写死位移不处理清屏T7devicePixelRatio适配离屏Canvasdestroy不做Retina适配不释放监听器T8分析数据量再选型try/catch包存储防抖保存盲目选IndexedDB或localStorageT9Web Worker主线程不阻塞Worker不能操作DOM不知道transferable忽略结构化克隆开销T10pushState监听popstate服务端回退防重复触发刷新404后退时状态被重复初始化6.2 六个最容易被忽略的实战错误这套题在给新人试跑和面试模拟里用下来最后暴露的问题高度集中在六个方向。第一把section当成万能区分块。section在HTML5里的语义是“一个带标题的内容分区”不是给所有区块套壳的工具。一个没有标题的分区多数情况下用div更诚实。第二音视频练习永远在桌面浏览器里完成。桌面Chrome播放正常不代表iPhone的Safari正常更不代表微信内置浏览器正常。视频题的核心从来不是标签属性而是编码、真机、策略这三个维度的组合。第三Canvas动画不看设备像素比。一个Retina屏就足以让所有看起来精致的粒子变成马赛克。这是“移动端兼容”里最常被忽略的硬指标。第四对本地存储过于乐观。能存、够存、异常时怎么办是三个问题。很多人答到第二层就停了其实第三层才是项目里真正会踩到的。第五Worker只是“另一个线程”不是万能钥匙。不能因为主线程卡就丢给Worker还要考虑大数据传输的克隆成本。存数字用ArrayBuffer转移存对象要谨慎。第六History API配好后不处理刷新。前端路由写得再好服务器不配合刷新一次就404这个坑特别隐蔽因为它只在部署后出现。6.3 如何把这份答卷变成项目规范我的习惯是每个新项目开始前拿这套题当“体检报告”。如果团队里有刚入行的同学我会先让他做一遍然后对照答案逐题聊。不想让“会写页面”变成一句空话这套卷子里的每一个考点都应该沉淀成项目里最基础的规范语义化不只是为了SEO更是给后续维护和自动化测试降低难度视频播放器必须有一张真机兼容测试表Canvas动画必须包含销毁逻辑所有本地存储操作必须有异常兜底凡是可能刷新404的路由第一天上线前就要验证部署配置。这套卷子唯一的遗憾是HTML5能聊的远不止这些。拖拽API、SSE、WebSocket、Service Worker离线缓存、Content Editable这些方向都没能塞进本次的10题里。但作为系列第六套它已经有足够高的密度了。做完这套考卷你会发现所谓“HTML5实战能力”其实就是把规范、浏览器策略、真机差异和异常兜底这四件事串起来的能力。这不是一朝一夕能背出来的但它恰恰是每个做网页设计、写前端交互的人每天都在经历的事。