動態

詳情 返回 返回

告別 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 加了層嵌套和作用域,調試起來頭大。粉絲的辯護聽着像在找藉口。以下是一個簡單的示例:

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 口碑一般,但問題在哪?很多人誤以為它是約束求解器。看這例子:

<div>
  <div style="height: 50%">...</div>
  <div style="height: 50%">...</div>
</div>
<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 時代,今天的我們也有機會重新定義瀏覽器的未來。

user avatar shuyuanutil 頭像 danjuanfe 頭像 bianchengsanmei 頭像 chaoqipengbodehanbaobao 頭像 judei 頭像 huaihuaidedianti 頭像 cason6810 頭像 sucre_199782 頭像 software-Development 頭像 ishy 頭像
點贊 10 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.