Lightbox Refactor(圖片/影片瀏覽器重構)
這次重構前列下的目標有:
- 解決部分使用者不習慣滑鼠點擊黑邊不能關閉 Lightbox 的不方便
- 改善狀態切換動畫流暢度
- 現有三層架構(Carousel、Interaction Detection、Video Control Overlay)跟泛型(Carousel<T>, T ∈ Default, Editor)過度複雜問題
- 修好 pinch 手勢放大圖片時錯誤使用畫面中心點作為參考點的問題
實際跳下去之後才發現問題比想像中麻煩:
- Lightbox 狀態管理太過複雜,常有兩到三層以上的 props 傳遞
- 既有 Flex/Grid box model 容易觸發 browser reflow
- 原本的 pan 完全依靠 top/left 移動圖片,過度依賴瀏覽器的 flow engine,無法善用 Hardware Acceleration
- double tap zoom-in 有跟 pinch 手勢相同的問題
- pan 的 boundary 錯誤設定在 w-screen/h-screen 的圖片 wrapper 上,移動圖片計算邊界會包含黑邊
- letterbox/pillarbox(水平/垂直貼齊邊緣)計算完全依賴 window.clientHeight/Width,顯示範圍不可能為了提供滑鼠點擊的黑邊而修改
- 將 Lightbox 關閉行為 defer 後,瀏覽器的上一頁行為無法預測,pop history 時經常會在非預期的時間點觸發 state update 打回 lightbox,觸發雙重關閉截斷切換動畫
- 縮放手勢鎖定之後會阻擋觸控裝置的橫向捲動
- 既有 scroll event 偵測圖片 pan-to-close(觸控裝置常見的拖曳圖片以關閉)的方式在某些裝置上無法確定使用者手勢何時結束,常會有手指尚未放開前圖片就自己關閉的問題
- 黑邊出現位置無法預測難以綁定點擊事件
在經過三天的痛苦之後,決定使用整套全新的架構處理上述問題:
- 轉用 Context 跟 Compound Component 的組合
- 與狀態切換相關的行為使用 React 19.2 ViewTransition 搭配 startTransition
- 搭配 use-gesture library 設定 event threshold
- zooming 時針對事件位置進行 offset 補償,同時使用 transform: translate/scale 調整圖片顯示位置
- 使用 motion 的 MotionValue 及 useTransform 隨需計算與動畫相關的狀態
- 自行維護 useResizeObeserver,觀測 wrapper 大小變化
- CSS media selector 針對模糊/精準游標裝置分別提供不同的 Lightbox pointer event 穿透

