仅靠CSS、HTML复刻《DOOM》,程序员极限“整活”:把div元素当3D游戏引擎用

张开发
2026/4/16 8:27:29 15 分钟阅读

分享文章

仅靠CSS、HTML复刻《DOOM》,程序员极限“整活”:把div元素当3D游戏引擎用
编译 | 苏宓出品 | CSDNIDCSDNnews多年来“HTML、CSS 到底算不算是编程语言”一直是前端圈一个颇具争议的话题。一边是工程师坚持认为它们只是标记与样式描述工具不具备传统意义上的逻辑能力另一边则认为在现代浏览器体系下CSS 已经具备足够复杂的表达能力甚至可以完成一些超出“样式表”范畴的工作。争论还没完全有结论一个更“实战化”的例子就出现了。来自荷兰的开发者 Niels Leenheer 近日做了一件看起来有点离谱的事他没有使用 WebGL也没有依赖任何游戏引擎仅仅依靠最基础的 HTML 和 CSS就复刻出了一个“能玩的《DOOM》”。在这个被称为 cssDOOM 的项目里墙壁、地板、木桶、甚至恶魔怪物都不是传统意义上的图形资源而是通过一个个在三维空间中不断变形的 div 标签构建出来的。JavaScript 只负责游戏逻辑与主循环而所有画面的渲染工作则完全交给 CSS 来完成。项目地址https://github.com/NielsLeenheer/cssDOOMNiels Leenheer 是谁Niels Leenheer 是一位资深开发者他最为人熟知的创建了是 HTML5 标准测试网站 HTML5test.com以及浏览器用户代理解析工具 WhichBrowser。同时他也是 Fronteers 大会委员会的成员。此前他曾完成一项趣味实验成功在示波器上运行《Doom》并借此编写代码从原版游戏 WAD 资源文件中提取地图数据。本次 CSS 版《Doom》正是在该实验的基础上迭代开发而来。纯靠 HTML、CSSDoom 是怎么实现的Niels Leenheer 首先将提取的游戏地图数据编译为由数千个div元素构成的静态场景。div classwall style --start-x: 2560; --start-y: -2112; --end-x: 2560; --end-y: -2496; --floor-z: 32; --ceiling-z: 88;每一个元素都标注了《Doom》原始坐标参数。随后浏览器的布局与合成系统会接管渲染工作通过 CSS 的 transform 以及诸如 hypot()、atan2() 等数学函数把这些元素渲染成定位在三维空间中的对象。.wall { --delta-x: calc(var(--end-x) - var(--start-x)); --delta-y: calc(var(--end-y) - var(--start-y)); width: calc(hypot(var(--delta-x), var(--delta-y)) * 1px); height: calc((var(--ceiling-z) - var(--floor-z)) * 1px); transform: translate3d( calc(var(--start-x) * 1px), calc(var(--ceiling-z) * -1px), calc(var(--start-y) * -1px) ) rotateY(atan2(var(--delta-y), var(--delta-x)));}与其让 JavaScript 负责完整的三维几何计算这个实现选择了一种更“偷懒”的方式脚本只传递原始的坐标点以及地板和天花板的高度等参数作为自定义属性其余诸如墙体宽度、旋转角度等三角计算全部交给 CSS 引擎来完成。这种分工是有意为之的游戏核心循环逻辑改编自《毁灭战士》开源 C 语言代码由 JavaScript 负责运行同时仅向 CSS 开放坐标数据、状态参数与少量自定义属性构成轻量化渲染层。Niels Leenheer 也曾尝试把游戏状态和逻辑完全交给 CSS 来处理但很快发现并不现实于是放弃了这一思路不过渲染路径依然几乎完全留在样式层完成。整个项目中一个关键难点在于如何把《DOOM》的坐标体系和渲染技巧适配到浏览器的 3D 处理方式上。比如地面就是通过将 div 元素绕 X 轴旋转 90 度来实现的然后再借助 clip-path 的 polygon()或更新的 shape() 语法将其裁剪成任意形状的扇区多边形从而支持复杂轮廓甚至奇偶填充规则。在不同区域之间实现无缝纹理铺设的关键是将背景位置锚定在“世界坐标系”中。例如如果一个元素在水平和垂直方向分别偏移了 200px 和 400px那么它的 background-position 就会被设置为 -200px -400px这样纹理图案就能像被连续铺在一整块平面上一样对齐。场景的移动方式也比较特殊它并不是通过“摄像机”来移动视角因为 CSS 本身并没有真正的摄像机概念而是通过移动整个“世界”来实现效果。JavaScript 会记录玩家的位置和角度并将其存储在四个自定义属性中而 CSS 会对这些数值进行反向计算使场景朝相反方向移动同时通过额外的 translate 来补偿透视效果其余部分则交给浏览器的渲染系统完成。敌人和投射物的精灵渲染则依赖“广告牌billboard”技术CSS 会让每个 sprite 始终面向观察者在需要时通过 scaleX 进行镜像翻转并使用 step() 动画来推进精灵帧序列而 JavaScript 只负责更新对应的状态属性。场景光照、自动门、升降平台、弹道特效统统被转化为可动态变更的样式状态问题。区域亮度以级联自定义属性存储搭配亮度滤镜统一调暗昏暗区域无需逐个修改场景元素游戏大门通过自定义属性绑定 CSS 过渡动画实现抬升开合脚本仅需切换状态标签动画播放完全交由浏览器原生驱动。弹药弹道通过起点、终点坐标与飞行时长定义CSS 依靠位移动画完成弹道位移搭配独立旋转属性让投射物始终朝向玩家。现代布局特性还被巧妙用来实现游戏自适应适配。原版固定宽度的状态栏被重构为文档对象模型独立组件弹药数值、生命值、角色头像、护甲值、钥匙道具拆分展示通过弹性布局自动排版在窄屏设备上自动换行适配。观战模式则新增一套 CSS 镜头逻辑。跟随视角利用角度正弦、余弦函数结合计算属性测算偏移数值将镜头固定在玩家斜后方与斜上方视角切换依靠独立的位移、旋转属性让第一人称与第三人称跟随视角之间实现丝滑过渡。性能与画面精度问题也暴露了这套纯 CSS 方案的固有短板。包含数千个三维变形元素的大型地图极易导致移动端苹果浏览器出现画面卡顿甚至程序崩溃。为此Niels Leenheer 加入视域剔除机制自动隐藏玩家视野外的几何模型。基础版剔除逻辑由 JavaScript 编写遍历场景元素根据距离与角度切换隐藏属性。Niels Leenheer 还测试了纯 CSS 剔除方案通过样式参数定义可见性判定结合延时动画与关键帧规则利用样式特性实现元素的自动显示与隐藏。局限性《Doom》原生渲染的部分核心逻辑很难直接复刻至 CSS 环境。原版游戏会将天空纹理以纯二维形式绘制在地图实体前方的虚拟墙体上而CSS渲染必须构建完整三维空间天空图层需要置于所有景物后方。这一差异会导致原版被天空遮挡的模型暴露出来Niels Leenheer 只能额外增加剔除规则隐藏玩家视角中被天空墙体遮挡的物体。Niels Leenheer 明确表示该项目绝非 WebGL、WebGPU 专业图形渲染方案的替代品性能瓶颈也客观存在但这并非本次开发的核心目的。他在分享中提到这项开发旨在突破 CSS 的能力边界。三角函数运算、自定义属性动画、裁剪路径、SVG滤镜、锚点定位等成熟商用级 CSS 特性都被赋予了标准制定者从未设想过的全新用途。最终成品完整可玩直观证明只要合理运用大量div元素与现代 CSS 语法无需调用任何图形编程接口就能在浏览器中完整复刻《毁灭战士》的游戏世界。长久以来爱好者不断挖掘各类低门槛、非常规设备运行《毁灭战士》的可能性CSS 只是最新的趣味载体。也正如 Niels Leenheer 所言如果说还有什么意义的话那它至少回答了一个没人真正问过的问题CSS 能不能跑《DOOM》答案是可以。确实可以。来源https://nielsleenheer.com/articles/2026/css-is-doomed-rendering-doom-in-3d-with-css/https://www.techspot.com/news/111922-developer-rebuilds-doom-using-only-css-html-turning.html推荐阅读弃用Windows、封杀Teams8万人紧急迁移法国政府宣布“去微软化”全面转向Linux找技术、链资源、学出海7城论坛智能硬件的“全能加速包”来了面向 Ascend 950CANN 技术架构的变与不变【活动分享】48 小时与 50 位大厂技术决策者共探 AI 落地真路径。由 CSDN奇点智能研究院联合举办的「全球机器学习技术大会」正式升级为「奇点智能技术大会」。2026 奇点智能技术大会将于 4 月 17-18 日在上海环球港凯悦酒店正式召开大会聚焦大模型技术演进、智能体系统工程、OpenClaw 生态实践及 AI 行业落地等十二大专题板块特邀来自BAT、京东、微软、小红书、美团等头部企业的 50 位技术决策者分享实战案例。旨在帮助技术管理者与一线 AI 落地人员规避选型风险、降低试错成本、获取可复用的工程方法论真正实现 AI 技术的规模化落地与商业价值转化。这不仅是一场技术的盛宴更是决策者把握 2026 AI 拐点的战略机会。

更多文章