# ADR-0004：版面使用遞迴分割樹而不是絕對定位

已採用

## 狀態

已採用

## 背景

版面編輯器的資料模型有兩種常見選擇：

1. **絕對定位**：每個元素有 x、y、寬、高，可以自由拖曳與重疊。
2. **遞迴分割**：任何區塊都可以被切成兩塊，切出來的每一塊又可以繼續切。

## 決策

核心資料模型使用遞迴分割樹，比例而非像素。

```ts
type LayoutNode = { type: "split"; direction: "horizontal" | "vertical"; ratio: number; first: LayoutNode; second: LayoutNode } | { type: "slot"; content: SlotContent | null };
```

## 理由

**自由拖曳會產生無效的版面。** 元素重疊、留下無法解釋的空隙、超出畫布邊界——這些狀態在絕對定位模型裡全都是合法的，然後在現場的螢幕上變成一團混亂。分割樹在結構上就不可能產生重疊或空隙。

**RWD 只有在比例模型下才成立。** 存「左邊 1344px」的版面換一台螢幕就歪了；存「左邊 0.7」的版面在任何尺寸都是 70%。這對一個明確要支援 1080p、4K 與直式螢幕的產品是必要條件。

**幾何可以完整測試。** 分割樹的算繪是一個純函式：輸入樹與畫布尺寸，輸出每一塊的矩形。這讓「後台看到的和裝置播出來的一模一樣」變成可以用單元測試斷言的事，而不是靠人眼比對。

**操作也比較好懂。** 「把這一塊切成上下兩半」比「把這個框拖到那個座標，然後對齊」更容易做對，尤其是在需要鍵盤操作的無障礙情境下。

## 後果

- 做不出重疊的元素（例如浮在影片上的半透明字幕列）。這在數位看板的使用情境裡不常見，而且可以用未來的「圖層」機制補上，不需要放棄分割樹。
- 比例需要下限與上限（0.05 到 0.95）。沒有限制，使用者一不小心就會拖出 0.001 / 0.999 這種再也點不回來的版面。
- 刪除區塊實際上是「移除它的父分割」——兄弟節點會頂上來。直接刪掉插槽會留下只有一個孩子的分割節點，那種樹沒有幾何意義。

## 替代方案

**CSS Grid 風格的網格**：比自由拖曳結構化，但要表達巢狀的不對稱切分（左邊 70%，右邊再上下對切）就得引入複雜的跨列跨行語法。分割樹用兩層節點就表達完了。

**自由拖曳加上吸附輔助**：改善了體驗，但沒有解決根本問題——資料模型仍然允許無效狀態。
