畫布沒有 HTML:Figma 如何從零把無障礙做回來

一個 Figma 檔案不管幾百個圖層,畫布上只有一個 input。他們怎麼在底下長出一套 Mirror DOM,讓看不見螢幕的人也能逐層走過一份設計?

Building accessibility into a canvas-based product | Figma 官方文章封面

Figma 的畫布跟電玩遊戲是同一種東西——它把畫面渲染的工作從瀏覽器手上接過來,自己畫。這樣才撐得起無限縮放、多人即時協作這些重度功能。代價藏在看不見的地方:瀏覽器本來免費附贈的無障礙能力,整套消失了。

一個 Figma 檔案裡不管有幾百個圖層,畫布上只有一個 <input> 元素在接收焦點。對螢幕報讀器(screen reader)來說,這整張畫布看起來就是一個巨大、空白、沒有內容的方塊。

工程師 David Winslow 和產品經理 Elynn Lee 這篇文章,拆解 Figma 怎麼在畫布底下偷偷長出一套「Mirror DOM」,讓看不見螢幕的人也能用鍵盤逐層走過一個檔案、聽見每一次修改被念出來。

◆ SOURCE · FIGMA BLOG
Building accessibility into a canvas-based product
The canvas doesn't come with the standard HTML elements that make the browser accessible. Here's how we built accessibility in, from scratch.
David Winslow & Elynn Lee · Inside Figma · 2026.07.01
閱讀英文原文 →
▲ 撐起無障礙的四個系統
01
內部無障礙樹
Internal accessibility tree — 快取每個圖層的無障礙資訊,只做外科式更新
02
Mirror DOM
一組 React 元件,依無障礙樹把真的 DOM 元素放進頁面
03
選取/焦點雙向同步
Bidirectional sync — 畫布選取與系統焦點兩邊對齊
04
動作播報系統
Announcement — 把 nudge、切換工具這類看得見的動作念出來
目錄 · CONTENTS
01先認識「無障礙樹」這個東西
02Figma 的解法:四個系統合力造 Mirror DOM
03內部無障礙樹:替每個圖層寫一句摘要
04Mirror DOM 為什麼刻意「不隱藏」
05焦點與選取,必須走在同一步
06把看得見的動作,念給聽的人
01 / 06
先認識「無障礙樹」這個東西
The accessibility tree

瀏覽器引擎裡有一個叫「無障礙樹」(accessibility tree)的資料結構,是從整份文件蒸餾出來、專門給輔助科技用的非視覺資訊。當一位報讀器使用者下「跳到下一個表單欄位」的指令,就是這棵樹告訴報讀器該往哪裡去。

瀏覽器怎麼長出這棵樹?靠 DOM、語意化的 HTML 標籤、ARIA 屬性,再加上一些額外運算出來的狀態。一般網頁裡每個元件都有自己的 DOM 元素——<button><p><img>。但 Figma 的畫布只有一個 <input>,於是瀏覽器替 Figma 建出來的那棵樹,幾乎是空的。

▶ TRY THIS
打開任一個 Figma 檔案,按 Tab 鍵在圖層之間移動,先感受一下純鍵盤導覽的節奏——這正是報讀器使用者每天在做的事。
02 / 06
Figma 的解法:四個系統合力造 Mirror DOM
How the system works

Figma 畫布真正渲染的資料結構叫 scenegraph——一棵由節點組成的樹。他們的做法是:在畫布背後、看得見畫面的人完全察覺不到的地方,渲染出一批「鏡像」DOM 元素,只映射 scenegraph 裡對輔助科技有意義的部分。

這套機制由四個系統合作完成:一棵快取所有圖層無障礙資訊的內部樹、一組把元素真的塞進 DOM 的 Mirror DOM 元件、一套讓畫布選取與系統焦點雙向同步的機制,以及一個負責把各種修改念出來的播報系統。下面這張官方流程圖,把「一個圖層」如何一路變成報讀器讀得到的內容講得很清楚。

Figma accessibility pipeline diagram
圖層 → accessible summary → Mirror DOM(JSX)→ 無障礙 API。圖/Figma
03 / 06
內部無障礙樹:替每個圖層寫一句摘要
The internal accessibility tree

Figma 從「瀏覽器最終需要知道什麼」反推回去,自己造了一棵內部無障礙樹。它替文件裡的每一個圖層,產生一段會被報讀器念出來的「accessible summary」。

這段摘要會隨情境改變。在 prototype 裡,多數編輯功能可以省略,只把最終觀看者需要的內容留下——文字欄位就念文字,有點擊互動的元件就給它一個 button 的角色。反過來,autolayout frame 在 prototype 裡被排除,但當使用者在編輯文件時就必須放進來。摘要做完後,系統由上往下走一遍整棵樹,把被省略的節點壓平。第一次載入文件時整棵樹會完整建好,之後則全程盯著每一次編輯,做外科式的局部更新,避開整棵重建的昂貴成本。

▶ TRY THIS
養成幫圖層命名的習慣。你在圖層面板打的每個名字,都會被報讀器直接念出來——隨手留著的「Frame 427」對聽的人毫無意義。
04 / 06
Mirror DOM 為什麼刻意「不隱藏」
The Mirror DOM

建好無障礙樹之後,就能生成 DOM。這件事交給一個會遞迴渲染自己的 React 元件:每個實例只訂閱某一個特定圖層在無障礙樹上的變化,圖層變了,React 幫忙把 DOM 的改動也壓到最小。

有一個細節會讓人意外——Figma 沒有用常見的「視覺上隱藏」手法來處理這些看不見的內容。原因是:一份 Figma 文件的空間佈局本身就承載著意義,就算不顯示畫面,這些元素的位置依然餵給輔助科技使用。螢幕放大鏡會平移畫面、把聚焦的元素留在視野內;報讀器會替弱視使用者畫出高對比外框;語音控制工具也會在畫面上標出提示。每個圖層都帶著一個 affine transform(仿射變換),記錄位移、縮放、旋轉,Figma 用它把這些元素透過 CSS 精準擺到對的位置,連旋轉和傾斜都還原。

Illustration of hands navigating colorful interfaces
空間位置本身就是意義的一部分。圖/Figma,插畫 María Medem
05 / 06
焦點與選取,必須走在同一步
Keeping focus and selection in lockstep

焦點(focus)是系統層級的鍵盤屬性,標記使用者此刻正在互動的元素。對報讀器和純鍵盤使用者來說,按 Tab 應該讓焦點依視覺佈局在頁面上移動。

麻煩在於「選取」和「焦點」不一定是同一個東西——想像你從下拉選單挑了一項,再按 Tab 把焦點移到送出按鈕。在 Figma 畫布裡,Tab 會改變被選取的節點,卻不動系統的鍵盤焦點,於是整張畫布在報讀器眼中看起來就是一個巨大的導覽目標。Figma 因此在 Mirror DOM 裡做了雙向同步:點畫布時,正確的項目會替報讀器取得焦點;報讀器動作移動了焦點時,畫面上的選取高亮也跟著更新。連 VoiceOver 的 rotor 這種控制項,都能因此直接選到畫布裡的節點。

▶ TRY THIS
在 Mac 上按 Cmd + F5 開 VoiceOver,打開一個 Figma prototype,試著用 rotor(VO + U)跳選節點——親耳聽一次,你對「無障礙」的體感會完全不同。
06 / 06
把看得見的動作,念給聽的人
Announcing actions and changes

前面兩套系統把 Figma 檔案的內容攤開給輔助科技,但光這樣不夠用來編輯——編輯時,應用程式必須把使用者的動作回報給他。像 nudge(用方向鍵微調位置)這種對明眼人一目了然的手勢,也需要提供可以被念出來的文字。

做法只有一種:靠 ARIA 標準裡的 live region。Figma 替產品裡每一個 toast 提示都加上 live region 標記,並支援「隱形播報」——那些明眼人看了只會覺得吵的事件(例如每按一次方向鍵就跳一個 toast),對無障礙卻很重要。他們還做了自動「合併」(coalescing):同類事件在很短時間內連續發生就併成一則。連按五次方向鍵各移一像素,系統會送出一句「移動了 5 像素」,取代把「移動了 1 像素」念五遍。

▲ 合併播報 · COALESCING
連按方向鍵 5 次
↓ 移動了 1 像素
↓ 移動了 1 像素
↓ 移動了 1 像素
↓ 移動了 1 像素
↓ 移動了 1 像素
報讀器只念一句
「移動了 5 像素」
▶ TRY THIS
到 Figma 設定裡打開「Adapt content for screen readers」,讓報讀器拿到最佳化過的內容——這個開關在 Design、Dev Mode、Slides 都能用。
整體觀察 /
一件永遠做不完的事
What's in place, and what's next

Figma 的無障礙工程走了好幾年,靠著和無障礙顧問機構 Fable 的合作,持續收進真實輔助科技使用者的回饋。它從 2022 年的 Prototype 觀看器開始,2023 年做到 FigJam,2024、2025 兩年推出「Adapt content for screen readers」設定、第一版畫布鍵盤控制、加強對比模式,還有十五項以上的無障礙改進。

對正在學 Figma 的你,有幾個當下就能用的成果:色彩選擇器會告訴你一組配色是否符合無障礙準則;替可見圖層改名字,名字會傳給報讀器;而新的 check designs 功能能把你的設計對照 design system,一鍵標出低對比、建議符合 WCAG 2.0 AA 或 AAA 的顏色,讓你在交付給工程師之前先修掉。無障礙這件事永遠不會真正完成,每補上一塊,就替更多人移走一道參與創作的障礙。

“Accessibility work is never really finished. Each improvement helps remove another barrier, making it possible for more people to participate in the creative process.”
無障礙這件事永遠不會真正完成。每一次改進,都替更多人移走一道障礙,讓他們得以參與創作。
— David Winslow & Elynn Lee, Figma
◆ 重點整理 · KEY POINTS
① 畫布自己接管渲染 → 換到效能,也丟掉瀏覽器免費的無障礙。
② 解法是 Mirror DOM:在畫布底下鏡射出真的 DOM 元素給輔助科技用。
③ 內部無障礙樹替每個圖層寫「摘要」,隨情境變、只做局部更新。
④ 鏡射元素刻意不隱藏,因為空間位置本身就是意義(affine transform + CSS)。
⑤ 選取與焦點雙向同步;ARIA live region 把動作念出來,還會合併成「移動了 5 像素」。
FIGMA 全攻略
無障礙做得好,前提是元件思維夠扎實
Mirror DOM、accessible summary 這些工程細節,回到設計端就是「圖層命名、component、對比度」的日常功。Figma 全攻略從底層邏輯帶你把 component、variables、Auto Layout 一次練透,讓你交付的檔案本身就好懂、好接手。
看課程 →
AI 覺醒設計應用攻略
每天一篇,把設計工具的最新動態變成你的技能
Figma、Adobe、Claude 的官方更新每天在跑,AIWAKEN 幫你濾成「看得懂、用得上」的中文拆解,讓你不必自己啃英文原文也能跟上工具演進。
了解訂閱 →