编译 | 苏宓
出品 | CSDN(ID:CSDNnews)
多年来,“HTML、CSS 到底算不算是编程语言”一直是前端圈一个颇具争议的话题。
一边是工程师坚持认为,它们只是标记与样式描述工具,不具备传统意义上的逻辑能力;另一边则认为,在现代浏览器体系下,CSS 已经具备足够复杂的表达能力,甚至可以完成一些超出“样式表”范畴的工作。
争论还没完全有结论,一个更“实战化”的例子就出现了。
来自荷兰的开发者 Niels Leenheer 近日做了一件看起来有点离谱的事:他没有使用 WebGL,也没有依赖任何游戏引擎,仅仅依靠最基础的 HTML 和 CSS,就复刻出了一个“能玩的《DOOM》”。
在这个被称为 cssDOOM 的项目里,墙壁、地板、木桶、甚至恶魔怪物,都不是传统意义上的图形资源,而是通过一个个在三维空间中不断变形的
标签构建出来的。JavaScript 只负责游戏逻辑与主循环,而所有画面的渲染工作,则完全交给 CSS 来完成。
项目地址:https://github.com/NielsLeenheer/cssDOOM
Niels Leenheer 是谁?
Niels Leenheer 是一位资深开发者,他最为人熟知的创建了是 HTML5 标准测试网站 HTML5test.com,以及浏览器用户代理解析工具 WhichBrowser。同时,他也是 Fronteers 大会委员会的成员。
此前,他曾完成一项趣味实验,成功在示波器上运行《Doom》,并借此编写代码,从原版游戏 WAD 资源文件中提取地图数据。
本次 CSS 版《Doom》,正是在该实验的基础上迭代开发而来。
纯靠 HTML、CSS,Doom 是怎么实现的?
Niels Leenheer 首先将提取的游戏地图数据,编译为由数千个`
`元素构成的静态场景。
">每一个元素都标注了《Doom》原始坐标参数。
随后,浏览器的布局与合成系统会接管渲染工作,通过 CSS 的 transform 以及诸如 hypot()、atan2() 等数学函数,把这些元素渲染成定位在三维空间中的对象。
}与其让 JavaScript 负责完整的三维几何计算,这个实现选择了一种更“偷懒”的方式:脚本只传递原始的坐标点,以及地板和天花板的高度等参数作为自定义属性,其余诸如墙体宽度、旋转角度等三角计算,全部交给 CSS 引擎来完成。
这种分工是有意为之的:游戏核心循环逻辑改编自《毁灭战士》开源 C 语言代码,由 JavaScript 负责运行,同时仅向 CSS 开放坐标数据、状态参数与少量自定义属性,构成轻量化渲染层。
Niels Leenheer 也曾尝试把游戏状态和逻辑完全交给 CSS 来处理,但很快发现并不现实,于是放弃了这一思路,不过渲染路径依然几乎完全留在样式层完成。
整个项目中一个关键难点,在于如何把《DOOM》的坐标体系和渲染技巧,适配到浏览器的 3D 处理方式上。比如地面,就是通过将
元素绕 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 特性,都被赋予了标准制定者从未设想过的全新用途。
最终成品完整可玩,直观证明:只要合理运用大量`
`元素与现代 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
【活动分享】"48 小时,与 50+ 位大厂技术决策者,共探 AI 落地真路径。"由 CSDN&奇点智能研究院联合举办的「全球机器学习技术大会」正式升级为「奇点智能技术大会」。2026 奇点智能技术大会将于 4 月 17-18 日在上海环球港凯悦酒店正式召开,大会聚焦大模型技术演进、智能体系统工程、OpenClaw 生态实践及 AI 行业落地等十二大专题板块,特邀来自BAT、京东、微软、小红书、美团等头部企业的 50+ 位技术决策者分享实战案例。旨在帮助技术管理者与一线 AI 落地人员规避选型风险、降低试错成本、获取可复用的工程方法论,真正实现 AI 技术的规模化落地与商业价值转化。这不仅是一场技术的盛宴,更是决策者把握 2026 AI 拐点的战略机会。
热门跟贴