原生HTML+CSS+JavaScript足够开发90%简单网页游戏,无需框架;关键掌握requestAnimationFrame驱动游戏循环、分离update/render逻辑、优先用DOM实现交互、localStorage存分数并注意协议限制。

用 HTML + CSS + JavaScript 写小游戏,根本不需要框架
新手一搜“HTML网页游戏框架”,容易被 Phaser、PixiJS 或各种“轻量框架”绕晕。其实,90% 的简单互动游戏(比如点击方块、接 falling blocks、走迷宫、文字冒险)完全不用引入任何外部库——原生三件套够用,且能真正理解每一步在干什么。
关键不是“选哪个框架”,而是先避开三个典型陷阱:
- 过早引入构建工具(
vite、webpack),反而卡在环境配置上 - 抄完整项目却不懂
requestAnimationFrame和事件循环的关系 - 把游戏逻辑和 DOM 操作混在一起,改个计分就全乱
requestAnimationFrame 是唯一必须掌握的“游戏循环”核心
所有帧动画、实时响应、物理模拟都靠它驱动。它比 setInterval 更准、更省电、自动适配屏幕刷新率。
最简结构长这样:
立即学习“前端免费学习笔记(深入)”;
function gameLoop() {
update(); // 更新状态:位置、分数、碰撞等
render(); // 渲染:修改 DOM 或 canvas 绘图
requestAnimationFrame(gameLoop);
}
gameLoop();注意点:
- 别在
update()里直接操作 DOM——先算好所有状态,再统一render() - 如果游戏暂停,就别调
requestAnimationFrame;恢复时重新调用gameLoop() - 移动端要加
{ passive: false }防止 touch 事件被浏览器吞掉
DOM 游戏 vs <canvas>:新手从 DOM 开始更安全
想做“拖动小怪打 Boss”或“点击变色格子”,直接用 div + style.transform + classList 就行,不用碰像素、坐标系、上下文。
示例:一个可点击的“能量球”
<div id="ball" style="width:60px;height:60px;background:#f06;border-radius:50%;cursor:pointer"></div>
const ball = document.getElementById('ball');
let energy = 100;
<p>ball.addEventListener('click', () => {
energy = Math.max(0, energy - 10);
ball.style.backgroundColor = <code>hsl(${energy * 1.2}, 100%, 50%)</code>;
if (energy === 0) ball.style.opacity = '0.3';
});优势:
- 调试直观:右键检查元素,立刻看到
style变化 - 无需处理 canvas 坐标转换、图像加载失败兜底
- 天然支持 CSS 动画、过渡、伪类(
:hover、:active)
限制:
- 超过 200 个动态元素会卡(这时才该切
<canvas>) - 复杂形变(旋转+缩放+阴影叠加)性能不如 canvas
本地存储分数?用 localStorage 别碰 IndexedDB
记最高分、关卡进度、皮肤选择,localStorage 足够。它简单、同步、API 少,出错率低。
写法必须带 try/catch——用户可能禁用或空间满:
function saveScore(score) {
try {
localStorage.setItem('gameHighScore', String(score));
} catch (e) {
console.warn('save failed:', e);
}
}
<p>function loadScore() {
try {
return Number(localStorage.getItem('gameHighScore')) || 0;
} catch (e) {
return 0;
}
}注意:
-
localStorage只存字符串,数值记得Number()或parseInt() - 不要存对象直接
setItem('obj', obj)——会变成[object Object] - 需要存对象?用
JSON.stringify()/JSON.parse()
真正容易被忽略的是:不同域名、HTTP/HTTPS、甚至 localhost:3000 和 file:// 协议之间,localStorage 完全不共享。调试时用 file:// 打开 HTML 文件,存的东西永远读不到——必须起个本地服务(npx serve 或 VS Code Live Server 插件)。



















