HTML5实战测验:从文档骨架到Canvas动效的完整指南
这套HTML5测验一不是书后习题那种填空选择而是把日常开发里真正绕不过去的点拎出来过一遍文档骨架、播放器兼容、Canvas绘图、综合动效。我见过太多人背了标签却写不出一个能在手机上正常跑的视频页也见过初学者一碰到心形曲线就发怵。所以这套题没有死记硬背只有你平时到底有没有动手写过。先约定一下答题规则每题先说场景再给一个参考实现最后留几个追问。建议你打开编辑器跟着敲一遍不要只看不写。自评标准在后面做完再看答案对不上也没关系重要的是知道错在哪。1. 发卷之前这套HTML5测验一到底想考什么HTML5本身是个很大的概念从标签到API从语义化到媒体处理覆盖面太广。把这套题命名为测验一不是要考HTML5规范里有多少个标签而是想验证三件事能不能写出结构干净的页面、能不能处理真实设备上的兼容问题、能不能用Canvas这类API做点看得见摸得着的东西。1.1 为什么用做项目的方式出题我见过很多简历写着熟悉HTML5结果让他写一个视频页面连source多源都写不出来让他做个爱心动画只知道用GIF。原因是大部分教程都是认识标签级别没有把知识点串成场景。这套题的所有题目都有一个共同特点它们都是你在接私活、做公司官网、写活动页时真正会碰到的需求。比如播放器兼容你不处理就有人打开页面看不到视频比如圣诞贺卡你不做降级方案低端安卓机上就是一片白屏。所以别把它当考试把它当一个试试水的项目合集。如果你能不看答案独立完成超过一半那你的实战基础已经比大多数初学者强了。1.2 答题约定与自评标准建议的时间分配是第一题15分钟第二题20分钟第三题40分钟第四题30分钟。做完不算完要把报错、异常、浏览器差异记录下来这比代码本身值钱。评分也不看做没做出来而是看三个维度结构是否语义化有没有用对header、main、section这类标签兼容方案是否完整不是只照顾Chrome性能有没有考虑比如粒子数量、动画帧率、循环里的开销这三条其实也是正式项目里code review最常看的点。后面每题我都会给一个参考实现但参考不等于唯一答案你完全可以写出更好的方案。2. 第一题文档骨架与语义化结构场景你需要为一个本地活动页搭建最基本的HTML5骨架要求语义清晰、移动端适配良好、SEO基础达标。请写出一个完整的页面开头部分包含文档类型、语言声明、字符集、视口设置和基本语义化布局标签。这道题看起来简单但恰恰是很多人栽跟头的地方。大部分初学者会写!DOCTYPE html然后就不管了但里面藏着不少细节。2.1 参考实现!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta namedescription content本地HTML5活动页包含视频、Canvas动画和贺卡组件 title本地活动页/title /head body header h1站点标题/h1 nav导航链接/nav /header main section h2活动介绍/h2 article具体内容独立成块/article /section /main footer address联系信息/address /footer /body /html这段代码的核心不是标签数量而是选对标签。header放页首信息nav放导航main是页面主体且只能有一个section表示带标题的区块article是能独立分发的完整内容footer放页脚和联系信息address专门放联系方式。2.2 为什么语义化比标签万能更值钱语义化标签不是给浏览器看的主要是给三类读者看的搜索引擎爬虫、读屏软件、以及三个月后回来看代码的你自己。搜索引擎靠标签判断页面结构优先级h1通常比div里加粗的文本权重高读屏软件会跳着读nav、main没有语义化视障用户在你的页面上基本寸步难行。实际开发里有一个细节main标签在一个页面中只能出现一次而section需要配标题。如果你写了一个没有标题的section就算有语义标签也不符合规范。HTML5的语义化不是拿标签当装饰品而是让结构和内容对上号。2.3 这道题最容易踩的三个坑第一个坑字符集声明位置太靠后。meta charsetUTF-8应该放在head的最前面、title之前因为浏览器在解析HTML时如果前面字节有乱码风险字符集声明越早越安全。第二个坑viewport写死缩放比例。contentwidthdevice-width, initial-scale1.0是最保守的写法不要随意加maximum-scale1.0那样会禁用用户缩放对无障碍体验是减分项。第三个坑忘掉lang属性。很多人写html不带langzh-CN结果浏览器翻译插件乱弹窗、读屏软件用英文音色读中文。这个属性随手写上能省很多麻烦。3. 第二题浏览器对HTML5播放器的兼容支持写一个不翻车的video场景产品要求页面嵌入一段mp4视频需要在Chrome、Firefox、Safari和主流国产浏览器同样是Chromium内核上都能播放。请写出兼容方案并回答为什么同一个mp4文件有的浏览器能播、有的不能上一题考的是文档骨架这一题考的是真实项目里最磨人的媒体标签兼容问题。不同浏览器对html5播放器的支持这个话题我至少被问过二十次每次都是同一个原因源文件编码格式不对。3.1 参考实现video controls width720 postervideo-cover.jpg source srcmeeting.mp4 typevideo/mp4 source srcmeeting.webm typevideo/webm source srcmeeting.ogv typevideo/ogg p你的浏览器不支持HTML5视频请升级浏览器或下载视频观看。/p /video这段代码的核心是source多源机制。浏览器会从上到下找第一个能解的视频源如果都不行就显示video标签里的文字提示。3.2 为什么同一个mp4有的浏览器放不了视频能不能播不只是看文件扩展名还要看容器格式和编码格式。mp4只是容器里面的视频流可能用H.264、HEVCH.265或AV1编码音频可能是AAC或MP3。关键点在于各浏览器对编码格式的支持并不一致。浏览器MP4/H.264WebM/VP9Ogg/TheoraChrome支持支持支持Firefox支持支持支持Safari支持macOS 11.3 部分支持不支持国产双核Chromium内核支持支持支持所以常见的问题就是源视频是H.265编码的mp4移动端的安卓机大多是Chromium内核可以硬解但桌面端的Safari对H.265的支持就非常看版本播不了就黑屏。解决办法是压一版H.264 Baseline或Main编码的mp4再配上WebM做备选这样覆盖面最广。3.3 播放器兼容里最容易忽视的细节MIME type不能瞎写。typevideo/mp4对应H.264AAC的mp4如果源文件编码不对光写对type也没用。另外type属性不写也能播浏览器会自己嗅探但写了能帮助浏览器更快跳过不支持的源。自动播放策略是另一个高发坑。用户一进页面就带声音自动播放会被Chrome、Safari直接拦截。如果你确实需要在加载后播放可以先把muted属性加上video autoplay muted playsinline loopplaysinline在iOS Safari上尤其重要不写的话视频可能自动进入全屏播放。这个属性是历史遗留的兼容性设置但到今天依然有效。3.4 浏览器之外的音频坑视频之外音频标签同样有坑。比如微信内置浏览器对Web Audio API的采样率兼容性很迷同一个音频文件桌面端正常安卓微信里播放会变速。这种问题调试起来非常痛苦我的经验是做媒体播放之前先确认目标机型不要默认所有浏览器行为一致。4. 第三题Canvas爱心烟花特效——从数学公式到粒子系统的完整拆解场景活动页需要一个点击后绽放爱心烟花的交互特效。请用Canvas实现一个心形粒子动画点击按钮后粒子排列成爱心形状散开并回落。这道题对没接触过Canvas的人来说会有点心理压力但拆开看其实就三层数学曲线生成点、粒子系统管理运动、渲染循环让画面动起来。4.1 心形曲线从哪里来网上流传最广的心形参数方程是x 16 * sin^3(t) y 13 * cos(t) - 5 * cos(2t) - 2 * cos(3t) - cos(4t)其中t的范围是0到2π。这个公式不是我发明的是很多绘图工具都在用的经典曲线。把t等分成几百个点每个点计算一个坐标就得到了爱心的轮廓。function generateHeartPoints(count 120, scale 8) { const points []; for (let i 0; i count; i) { const t (i / count) * 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); points.push({ x: x * scale, y: -y * scale }); } return points; }注意这里我把y取反了。原因是数学坐标系y轴向上但Canvas的坐标系y轴向下不取反爱心是倒着的。4.2 粒子系统的最小实现粒子系统听起来高大上核心就是一个对象数组加上每帧更新。每个粒子记录自己的位置、速度、颜色和生命值每帧先清屏再更新位置再绘制。class Particle { constructor(x, y, vx, vy, color) { this.x x; this.y y; this.vx vx; this.vy vy; this.color color; this.age 0; this.maxAge 120; } update() { this.x this.vx; this.y this.vy; this.vy 0.08; this.age; } draw(ctx) { const alpha Math.max(0, 1 - this.age / this.maxAge); ctx.globalAlpha alpha; ctx.fillStyle this.color; ctx.beginPath(); ctx.arc(this.x, this.y, 2, 0, Math.PI * 2); ctx.fill(); } }点击按钮时把心形点集作为初始位置每个粒子的速度朝外扩散一点就形成了爱心炸开的效果。btn.addEventListener(click, () { const pts generateHeartPoints(80, 8); for (const p of pts) { particles.push(new Particle( canvas.width / 2 p.x, canvas.height / 2 p.y, (Math.random() - 0.5) * 2, (Math.random() - 0.5) * 2, #ff4d6d )); } });4.3 渲染循环和性能控制动画不能只用setInterval一定要用requestAnimationFrame。它会在浏览器下一次重绘之前执行回调帧率更顺滑而且标签页切到后台会自动暂停不会白白耗电。function tick() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (let i particles.length - 1; i 0; i--) { particles[i].update(); if (particles[i].age particles[i].maxAge) { particles.splice(i, 1); } } for (const p of particles) { p.draw(ctx); } requestAnimationFrame(tick); } requestAnimationFrame(tick);性能上最大的坑是globalAlpha和fillStyle的频繁切换。每frame设置一次其实还好但如果你有几百个粒子每帧都设置颜色和透明度就会产生明显开销。优化思路是提前按颜色分组或者用ctx.globalCompositeOperation lighter做发光叠加效果的同时减少阴影类的重操作。4.4 Canvas高分屏模糊问题这是移动端最常见的问题之一。CSS里的canvas宽高是逻辑像素但手机屏幕是2倍甚至3倍物理像素直接画会导致画面发虚。解决办法是让canvas的buffer尺寸和物理像素对齐再通过scale把绘制坐标映射回来。const dpr window.devicePixelRatio || 1; canvas.width canvas.clientWidth * dpr; canvas.height canvas.clientHeight * dpr; ctx.scale(dpr, dpr);这个操作在做烟花、贺卡这类视觉效果时几乎是必须的不然小屏手机上锯齿感非常明显。5. 第四题HTML5圣诞贺卡——把动效、音效、排版塞进一张卡片场景圣诞节快到了你要用HTML5做一张可在微信里分享的贺卡。要求有飘雪效果、一颗可以闪动的圣诞树、点击铃铛发出声音而且不能在低端手机上卡死。请给出你的技术组合和关键实现。这道题是综合性最大的一题也是热搜词里html5圣诞贺卡的实际场景。它不要求你用多复杂的技术反而考验你怎么选型、怎么控制成本。5.1 技术组合不要什么都用Canvas我看到很多人的第一反应是只要动效复杂就上Canvas。但贺卡这种页面静态部分是绝大多数飘雪才是动态部分全屏Canvas反而浪费性能。更合理的分工是圣诞树、铃铛、文字排版用HTML CSS动画交给CSSanimation飘雪效果用Canvas处理因为雪花数量多、随机性强CSS逐个写div到五十个以上就明显卡顿音效用AudioContext临时合成铃铛声不需要额外音频文件这种组合的好处是首屏HTML就能渲染出静态内容CSS动画由GPU负责Canvas只处理真正需要动态绘制的部分性能压力散开了。5.2 圣诞树和铃铛的CSS动效圣诞树可以是一个简单的三角形叠加用CSS渐变生成不需要图片。铃铛可以用的小图标加一个挂绳摇晃动画.bell { display: inline-block; transform-origin: top center; animation: swing 1.2s ease-in-out infinite; } keyframes swing { 0%, 100% { transform: rotate(0deg); } 25% { transform: rotate(15deg); } 75% { transform: rotate(-15deg); } }transform-origin设为顶部中心动画才是挂在绳子上晃的效果不然会变成原地转圈。这种细节是纯靠背属性背不出来的得动手调。5.3 飘雪效果的轻量实现飘雪容易写但也要控制数量。桌面端100片没问题移动端建议30到50片就是上限多了低端机直接发烫。const canvas document.getElementById(snow); const ctx canvas.getContext(2d); const flakes Array.from({ length: 40 }, () ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, r: Math.random() * 3 1, speed: Math.random() * 0.8 0.3, wind: Math.random() * 0.4 - 0.2 })); function drawSnow() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle #ffffff; ctx.globalAlpha 0.8; for (const f of flakes) { ctx.beginPath(); ctx.arc(f.x, f.y, f.r, 0, Math.PI * 2); ctx.fill(); f.y f.speed; f.x f.wind; if (f.y canvas.height) { f.y -5; f.x Math.random() * canvas.width; } } requestAnimationFrame(drawSnow); } drawSnow();这里有个小技巧把雪花的初始y坐标随机铺满整个画布而不是从顶部出发不然刚进入页面时雪花会一窝蜂从顶部往下掉观感很差。5.4 用AudioContext合成铃铛声有些人一听到音效就找mp3文件其实一个简单的铃铛声不用采样用Web Audio API自带振荡器就能做。核心思路是高频正弦波加上快速衰减的增益包络听起来就有叮的质感。function playBell() { const ctx new (window.AudioContext || window.webkitAudioContext)(); const osc ctx.createOscillator(); const gain ctx.createGain(); osc.type sine; osc.frequency.value 1568; gain.gain.setValueAtTime(0.5, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime 0.8); osc.connect(gain); gain.connect(ctx.destination); osc.start(); osc.stop(ctx.currentTime 0.8); }注意AudioContext在部分浏览器里第一次点击时是suspended状态需要先resume()再播放否则不响。这也是不少人做完音效后发现没声音的原因。5.5 微信内置浏览器的降级策略贺卡一般是在微信里打开的微信内置浏览器基于Chromium内核整体兼容性不错但有两个点要注意。第一是Canvas的devicePixelRatio可能和普通浏览器不一致建议动态获取第二是全屏Canvas滚动时要监听resize和orientationchange重新设置canvas宽高不然横竖屏切换后画面会拉伸。更保险的做法是如果检测到设备很旧直接把雪花数量减半或者干脆用CSS动画做少许雪花。对用户来说看到的是一张不卡顿的贺卡而不是完美的物理模拟。6. 收卷之后成绩对应的能力画像与进阶方向做到这里这套HTML5测验一的核心题目就过完了。虽然名字叫测验但它并没有一个标准分数线我更愿意把答题情况分成三档能独立写完前两题说明页面结构与媒体处理的基本功是有的第二题开始卡壳大概率是平时只在Chrome里调试没有养成多浏览器验证的习惯第三题靠查资料做完说明Canvas基础概念能理解但缺少对数学曲线到坐标映射的练习多画几个图形就能补上第四题能跑起来但掉帧那么你缺的不是HTML5知识而是前端性能优化的sense。我自己做这类动效页面的经验是先让功能跑通再做视觉优化最后做性能优化。顺序反了会非常难受比如你先把粒子加了发光阴影效果结果发现掉帧严重还得回头删代码。下一步的练习方向可以这样走把第三题的爱心烟花改成跟随鼠标发射的流星把第四题的飘雪改成可以响应触摸的雪花堆叠都是很好的练手项目。如果想让手更稳再写一遍这些代码时试着不参考任何资料遇到卡住的API先查MDN别急着看别人的示例。这样写完你对HTML5的实际掌握就不是知道而是会做了。

相关新闻