告别 DOM 的旧时代:从零重塑 Web 渲染的未来

引言

浏览器这玩意儿现在真够诡异的。WebAssembly 在服务器端混得风生水起,但客户端还是那副老样子,跟十年前没啥区别。

WASM 粉会跟你吹,通过点 JS 胶水代码就能调原生 Web API。但核心问题是:为啥非得用 DOM?这东西就是个默认选项罢了。本文直击 DOM 和相关 API 的痛点,为什么该让它们退场了,顺便脑洞下怎么改进。

作者不是浏览器全栈专家------没人能全懂了,这正是症结所在:东西太杂太乱

DOM 的"文档"模型:臃肿得像个大胖子

DOM 烂到什么程度?Chrome 里document.body有 350+个键值,大致分类:

  • 节点操作:appendChild、removeChild之类的。
  • 样式相关:style对象塞了 660 个 CSS 属性。
  • 事件处理:那些过气的onevent属性,比如onclick,基本没人用了。
  • 杂七杂八:innerHTML、className等。

属性和方法界限模糊,很多 getter 会偷偷触发重排,setter 藏在暗处。还有一堆历史遗毒。

DOM 不瘦身,还在发福。你是否感受到这痛苦,取决于你是搞静态页还是 Web App。作为开发者,我们大多避开直接操 DOM,转而用框架。但偶尔有纯 DOM 党吹它牛逼------纯属自欺欺人。DOM 的声明式功能,比如innerHTML,跟现代 UI 模式八竿子打不着。同一件事 DOM 有 N 种方式,全都不优雅。

Web Components 的尴尬处境

Web Components 是浏览器原生组件方案,但来得太晚,人气不高。API 设计笨重,Shadow DOM 加了层嵌套和作用域,调试起来头大。粉丝的辩护听着像在找借口。以下是一个简单的示例:

JavaScript class HelloWorld extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({ mode: 'closed' }); const template = document.getElementById('hello-world').content.cloneNode(true); const hwMsg = `Hello ${this.getAttribute('name')}`; Array.from(template.querySelectorAll('.hw-text')).forEach(n => n.textContent = hwMsg); shadow.append(template); } } customElements.define('hello-world', HelloWorld);

看起来还行?但实际开发中,Shadow DOM 的复杂性和 DOM 的字符串化特性(stringly typed)让开发者头疼。相比之下,React、Vue 等框架的虚拟 DOM 完全避开了这些问题,因为它们的语法只是"长得像 XML",而不是真的依赖 DOM。

HTML 的停滞不前

HTML10-15 年没大动静。ARIA 是亮点,但只是补语义 HTML 的漏。语义 HTML 从 2011 年就开始推,但到现在都没<thread>或<comment>标签。嵌套<article>来模拟评论?指导原则也奇葩。

HTML 总像在嫉妒纸媒,没能真正拥抱超文本本质,也不信开发者能守规矩。

WHATWG(浏览器厂商)接管后,没啥愿景,就在边边角角加补丁。CSS 甚至长出了表达式------每个模板语言都想变编程语言。

编辑 HTML?contentEditable理论上行,但实际搞成可用编辑器是黑魔法。Google Docs 和 Notion 的工程师肯定有吐不完的槽。

渐进增强、 markup/style 分离?做 App 的开发者早不信这套了。

现在 App 大多用 HTML/CSS/SVG 拼凑 UI,但开销巨大,越来越不像正经 UI 工具箱。

比如 Slack 的输入框:用一堆 div 模拟富文本。剪贴板 hack 用隐藏元素。列表/表格得手动虚拟化,自管布局、重绘、拖拽。聊天窗滚动条粘底每次都得重写。虚拟化越深,越得重造页面搜索、右键菜单等。

Web 混淆了 UI 和流式内容,当年新鲜,现在过时。UI 陈旧,内容同质化。

CSS 的"内外倒挂":别用错心智模型

CSS 口碑一般,但问题在哪?很多人误以为它是约束求解器。看这例子:

HTML <div> <div style="height: 50%">...</div> <div style="height: 50%">...</div> </div>
HTML <div> <div style="height: 100%">...</div> <div style="height: 100%">...</div> </div>

第一个想分一半高?第二个自相矛盾?实际 CSS 忽略height,父元素收缩包裹内容。

CSS 是两趟约束:先外到内传尺寸,再内到外集内容大小。App 布局外到内:分空间,内容不影响面板大小。文档内到外:段落撑开父级。

CSS 默认内到外,文档导向。要外到内,得手动传约束,从body { height: 100%; }开始。这就是垂直对齐难的原因。

Flexbox 给显式控制:

用flex-grow/shrink做无溢出自适应布局,加 gap 间距。

但 Flex 混淆了简单模型:需先"猜测"子自然尺寸,布局两次------一次假设浮空,一次调整。递归深了可能爆栈,虽少见,但大内容一丢,一切变形。

避坑:用contain: size隔离,或手动设flex-basis。

CSS 有contain、will-change这类直击布局的,暴露底层层级本质。代替position: absolute包裹。

本质上,这些切断 DOM 全局约束流------默认太宽泛,太文档化

CSS 的好地方?

Flexbox 懂了这些坑,还挺靠谱。嵌套行列+gap,直观适配尺寸。CSS 好部分在这,但得用心打磨。Grid 类似,但语法太 CSS 味儿,啰嗦。

从零设计布局,不会这样:不会用减法 API 加屏障提示。会拆成组件,用外/内容器+放置模型,按需组合。

inline-block/inline-flex示意:内部 block/flex,外部 inline。盒模型两正交面。

文本/字体样式是特例:继承如font-size,为<b>工作。但 660 属性大多不继承------边框不递归子级,那会傻。

CSS 至少两东西混搭:继承的富文本样式系统 + 非继承的嵌套布局系统。用同语法/API 是错。

em相对缩放过时,现在逻辑/设备像素更 sane。

SVG 无缝入 DOM,动态形状/图标调色。但 SVG 非 CSS 子/超集,重叠处微差,如transform。坐标字符串化,烦。

CSS 加圆角/渐变/剪裁,有 SVG 嫉妒,但远不及。SVG 做多边 hit-testing,CSS 不行。SVG 有自己图形效果。

选 HTML/CSS 还是 SVG?基于具体 trade-off,全是向量后端。

注意一下的坑:

  • text-ellipsis只截单行文本,非段落。检测/测量文本 API 烂,大家数字母凑合。
  • position: sticky零抖动滚动固定,但有 bug。无条件 sticky 需荒谬嵌套,本该简单。
  • z-index绝对层级战,z-index-war.css 里 +1/-1 比拼。无相对 Z 概念。

API 设计难,得迭代建真东西,找漏。

SVG 与 CSS 的权衡

SVG 在 Web 中用于动态生成图形或调整图标样式,但它与 CSS 并非完全兼容。例如,SVG 的 transform 与 CSS 的变换属性有微妙差异,且 SVG 的坐标全是字符串序列化,增加了开发复杂性。

国内场景:假设你在开发一个数据可视化仪表盘,类似 ECharts 的柱状图。你可以选择用 SVG 绘制图形,或者用 CSS 实现类似效果。SVG 支持多边形点击检测(hit-testing),而 CSS 不行;但 CSS 的圆角、渐变等功能又让 SVG 显得多余。最终,你可能需要在两者间做痛苦的权衡

Canvas 上的油画:HTML in Canvas 的坑

DOM 坏,CSS 几成好,SVG 丑但必备......没人修?

诊断:中间层不合用。HTML6 先砍东西起步。

但关键解放现有功能。理想:用户空间 API 同逃生口,狗食自家。

HTML in Canvas 提案:画 HTML 到<canvas>,控视觉。不是好法。

API 形因塞 DOM:元素须 canvas 后代参与布局/样式/无障碍。离屏用有"技术关切"。

例子:旋转立方体交互用 hit 矩形+paint 事件。新 hit API,但只 2D------3D 纯装饰?问题多。

从零设计,不会这样!尤其浏览器有 CSS 3D transform,何须为自定义渲染全接交互?

未覆盖用例如曲面投影,需复杂 hit。想过下拉菜单吗?

像没法统 CSS/SVG 滤镜,或加 CSS shader。经 canvas 是剩选项。"至少可编程"?截 DOM 一好用,但非卖点。

Canvas 上复杂 UI 是为绕 DOM:虚拟化、JIT 布局/样式、效果、手势/hit 等。全低级。预备 DOM 内容反生产。

反应性上,路由回同树设循环。渲染 DOM 的 canvas 非文档元素了。

Canvas 真痛:无系统字体/文本布局/UI 工具。从零实现 Unicode 分词,就为包裹文本。

提案"DOM 黑箱内容",但知套路:还得 CSS/SVG 拼凑。text-ellipsis仍破,得从 90 年代 UI 重造。

全或无,要中道。下层需开。

未来的方向:重新设计 DOM

DOM 和 CSS 的问题根源在于它们背负了太多的历史包袱。以下是一些可能的改进方向:

  1. 精简的数据模型:未来的 DOM 需要大幅减少属性数量(从 350+精简到几十个),专注于核心功能。类似 React 的虚拟 DOM,但直接内置于浏览器中。在开发类似头条的信息流应用时,开发者需要快速渲染大量卡片。精简的 DOM 模型可以减少不必要的 API 调用,提高性能。
  2. 统一的布局系统:将 CSS 的内外布局模式明确分开,支持更直观的"外部约束"和"内部自适应"。例如,垂直居中应该像 align-items: center 一样简单。在电商平台的商品详情页中,开发者希望轻松实现复杂的布局(例如商品图片和描述的动态对齐),而不是依赖一堆 CSS hack。
  3. WebGPU 的潜力:WebGPU 提供了更底层的渲染能力,可以完全抛弃 DOM 的复杂性。例如,Use.GPU 项目展示了一个基于 WebGPU 的简洁布局系统,代码量仅为传统 DOM/CSS 的几分之一。在开发类似 B 站的弹幕播放器时,WebGPU 可以用来高效渲染动态弹幕,省去 DOM 的性能开销。
  4. 多线程与隔离:现代浏览器已经是多进程架构,但 DOM 的设计没有跟上。未来的 DOM 需要支持更好的多线程和跨源隔离,适应复杂的 Web 应用需求。在企业级应用(如钉钉的协作平台)中,开发者需要集成第三方服务(如 OAuth 登录)。一个支持多线程的 DOM 可以显著提高安全性和性能。

结论

HTML、CSS 和 DOM 的现状就像一辆老旧的马车,虽然还能跑,但早已不适合现代 Web 应用的复杂需求。国内开发者在开发小程序、电商平台或社交应用时,常常需要用框架和 hack 来弥补 DOM 的不足。未来的 Web 需要一个更精简、更灵活的渲染模型,可能基于 WebGPU 或全新的 API 设计。

与其修补 DOM 的漏洞,不如从第一性原理出发,重新设计一个适合现代应用的 Web 渲染层。就像当年的 Netscape 开启了 Web 时代,今天的我们也有机会重新定义浏览器的未来。

相关推荐
暖木生晖20 小时前
APIs之WEB API的基本认知是什么?
前端·dom·dom树·web apis
黑羽同学8 天前
Fix: 修复AI聊天输入框Safari回车发送bug
前端·javascript·dom
inx17719 天前
HTML/CSS/JS 是如何渲染页面的|浏览器渲染原理与性能优化基础
css·seo·dom
玉宇夕落20 天前
🚀 从 HTML 到像素:浏览器渲染全流程揭秘(附性能优化实战)
前端·dom
inx17723 天前
从拼接到优雅:用 ES6 模板字符串和 map 打造更简洁的前端代码
前端·javascript·dom
小时前端1 个月前
事件委托性能真相:90%内存节省背后的数据实证
前端·dom
小时前端2 个月前
5大DOM/BOM核心考点:从入门到精通,让面试官眼前一亮
dom
脑子慢且灵3 个月前
【Web前端】JS+DOM来实现乌龟追兔子小游戏
java·开发语言·前端·js·dom
wayhome在哪3 个月前
30KB 轻量王者!SortableJS 轻松搞定拖拽需求
javascript·设计·dom