HTML 規格:事件處理常式停用檢查移到編譯期
WHATWG HTML · 2026-09-24
HTML 規格把行內事件處理常式(例如 onclick 屬性)的「scripting 是否停用」檢查,從事件觸發當下的執行期判斷,搬到把屬性字串編譯成函式的編譯期判斷;呼叫時則改用與 DOM 規格一致的「document 是否仍為 fully active」判斷,取代原本過寬的檢查。這項異動由 WHATWG HTML 編輯 Anne van Kesteren 於 2026-09-24 提交 commit 1a249c2a40bd341f7c2c0c9954a9a264b1983b93,同步測試列在 web-platform-tests PR #62719,並依賴 whatwg/dom PR #1085 的新定義。
背景:規格文字跟實作對不上
HTML 規格描述事件處理常式有兩條路徑:一條是「取得事件處理常式目前的值」,負責把行內屬性字串(像 onclick="doThing()")編譯成可呼叫的函式;另一條是「執行事件處理常式」,也就是事件真正觸發時呼叫該函式的步驟。舊版規格把 scripting 停用檢查放在後者:「執行」演算法第一步就是「如果 eventTarget 的 scripting 已停用,則 return」,這個 scripting is disabled 概念涵蓋沒有 browsing context、使用者關閉 script、文件是 XSLT 產出等多種情況,範圍很廣。
真正把字串編譯成函式的步驟,卻只檢查了文件的 active sandboxing flag set 裡有沒有 sandboxed scripts browsing context 旗標,只是前述廣義檢查裡的一個子集。commit 訊息點出問題核心:實作「擋的是編譯內部原始未編譯 handler 這件事,而不是擋呼叫一個值已經是函式的事件處理常式」。瀏覽器真正卡關的時間點是把字串轉成函式的那一刻,一旦編譯完成,之後呼叫就不該再被寬鬆的 scripting is disabled 擋下——規格文字卻反過來,寬鬆檢查留在呼叫端、精確檢查缺在編譯端,兩邊顛倒,也讓照規格重寫實作或補測試的人難以對齊實際瀏覽器行為。
規格細節:兩處演算法互換檢查內容
這次 commit 動了 source 檔案的兩處演算法,共 +7 -5 行。第一處是「執行事件處理常式」:移除原本擺在最前面的 scripting is disabled 檢查,改在取得 callback 且確認非 null 之後,插入新步驟——如果 callback 所屬 realm 的 global object 是 Window,而其 associated Document 已經不是 fully active,就直接 return。第二處是「取得事件處理常式目前的值」:把原本只看 sandboxing flag 的檢查,換成完整的 scripting is disabled for document 判斷。
- If scripting is disabled for eventTarget, then return.
Let callback be ... If callback is null, then return.
+ If callback's associated realm's global object is a Window
+ object whose associated Document is not fully active, then
+ return.
- If document's active sandboxing flag set has its sandboxed
- scripts browsing context flag set, then return null.
+ If scripting is disabled for document, then return null.換句話說,編譯端拿到的是完整版 scripting is disabled 判斷;呼叫端則換成 DOM 定義的 fully active 判斷,兩邊各自對齊該對齊的規格概念,不再共用一個過寬的檢查。
影響範圍:瀏覽器引擎與 WPT 需要對齊
這是規格層面的演算法重排,直接受影響的是實作 HTML 事件處理常式的瀏覽器引擎——Chromium/Blink、WebKit、Gecko——而非一般網頁開發者的程式碼。三個引擎需要檢查自己在編譯行內 handler 屬性字串時,是否已經套用完整的 scripting is disabled 判斷(含使用者關閉 script、XSLT 產出文件等情境),而不只是 sandbox 旗標;同時要確認呼叫已編譯 callback(包含透過 el.onclick = fn 這類 IDL 屬性直接指派 function 的情境)時,改成只看 document 是否 fully active,不再受 scripting 狀態影響。
- 編譯端(getting the current value of the event handler):改用完整
scripting is disabled for document。 - 呼叫端(run the event handler for event):改用
document is not fully active,取代原本的scripting is disabled for eventTarget。 - 對應測試:
wpt#62719(HTML 端)與whatwg/dom#1085(fully active 定義端)。
對 web-platform-tests 的維護者而言,wpt#62719 補的是覆蓋這兩個檢查點的新測試案例,用來驗證「把字串編譯成函式」與「呼叫已編譯函式」該分別卡在哪個時間點;whatwg/dom PR #1085 則是 fully active 判斷本身在 DOM 規格那端的對應定義,兩份 PR 要一起看才能還原完整行為。
一般網頁開發者不需要因此更動程式碼,這是規格對齊瀏覽器實際行為的修正,而非新增行為。唯一需要重新驗證的族群,是那些用 sandboxed iframe(例如切換 sandbox="allow-scripts")或動態改變 document 存活狀態(如 iframe 被移除、頁面進出 bfcache)來測試 inline handler 邊界行為的自動化測試——舊規格文字描述的檢查點跟新版不同,測試斷言的時機也該對應更新。
原始來源:WHATWG HTML commit 1a249c2a、wpt PR #62719、whatwg/dom PR #1085