Safari 與測試

CSS interpolate-size: allow-keywordscalc-size():靜態 HTML 內聯高度動畫、Safari 真機驗收與雲 Mac 演練

MacHTML Lab2026.04.23約 31 分鐘閱讀

靜態導出的營銷頁依然大量摺疊面板、篩選抽屜與幫助說明,需要在零高度與自然內容高度之間順滑過渡,卻不想為每個斷點手寫像素表。多年裡業界只能回答“用 JavaScript 量 scrollHeight 再寫像素”,因為 height: auto 在計算值階段被視為不可插值的關鍵字。2026 年,interpolate-size: allow-keywordscalc-size() 把內聯測量重新放回樣式系統:你仍然按內容思考,卻能為 transition 提供數值走廊,但前提是理解層疊、flex/grid 默認最小尺寸,以及 WebKit 如何合併重排。本文覆蓋痛點、基礎能力、@supports 漸進增強、性能紀律、無障礙與決策矩陣,幫助靜態包體保持輕量且動效可信。若要把跨文檔過渡與頁內高度補間對照,請閱讀 靜態多頁應用的 View Transitions 指南;若摺疊區域裡還有隨內容增長的表單控件,請結合 field-sizing 與靜態表單,避免高度動畫與 textarea 內聯尺寸互相打架。

驗收成本同樣現實:在客戶同款 GPU 上覆現亞像素差異,租一臺 Mac mini 往往比把壞動畫推上線便宜。MacHTML 雲主機約 $16.9/天,下文把它當作演練預算的錨點。

為什麼動畫 height:auto 一直痛苦

常規 transition 能插值長度、百分比與部分 transform,但 height: auto 特殊:used value 依賴首次佈局後的內容測量。若寫 transition: height 240ms ease0auto 間切換,多數引擎在區間末尾直接跳變,因為缺少一對數字端點。於是出現 max-height: 9999px 這種“看起來順滑”的補丁:翻譯變長後時長與真實距離脫節,或佈局樹誤以為盒子可能無限高而浪費 GPU。JavaScript 讀取 scrollHeight 能救場,卻重新綁定主線程、讓靜態站 CSP 更難寫,並在 webfont 晚到動畫中途時閃爍。

新模型把測量留在樣式層:仍用內聯思維,但暴露可插值走廊。對禁止 React 狀態機的靜態導出、對 main.js 體積敏感的項目,這是結構性收益。Safari 優先團隊還要記得 WebKit 曾嚴防百分比高度與內聯關鍵字在 flex 子項裡循環解析——理解規範能避免把正確行為誤報為瀏覽器缺陷。

另一痛點是與圓角 overflow: hidden 共存:若只靠 max-height,陰影與 outline 繪製階段可能與內容揭示錯位,在 Retina 上像“雙開門”閃爍。內聯插值讓 used height 更貼近真實內容盒,前提是不要同時動畫無關屬性。

interpolate-size: allow-keywords 實踐

interpolate-size 讓子樹進入“關鍵字可插值”模式:在 disclosure 根設置 interpolate-size: allow-keywords,引擎才能把內聯關鍵字與長度之間的過渡視為可測量端點。寫作時通常放在 .disclosuredetails 外層,而不是全局 body,否則無關規則也會被拖入更大的插值表面,成本意外上升。

.disclosure {
  interpolate-size: allow-keywords;
  overflow: clip;
  transition: height 260ms cubic-bezier(.2,.8,.2,1);
}

與顯式 height 狀態配對:摺疊可為 0,展開仍可寫 auto,但引擎現在能走出數值軌跡。若用類名在 height:0height:auto 間切換,注意外邊距摺疊:相鄰 margin 可能留下“幽靈空隙”,QA 抱怨時把 margin 換到內層 padding 更穩。interpolate-size 會繼承:嵌套摺疊方便,但組件庫裡若子卡片誤繼承且同時動畫 flex-basis,在 Safari 可能觸發多輪佈局。用工具類收斂範圍,無動畫的靜態殼不要保留該屬性。

calc-size(fit-content) 作為測量橋

calc-size() 把內聯關鍵字包進可求長的計算,讓 transition 能採樣。常見寫法:展開態 height: calc-size(fit-content, size),瀏覽器按 height:auto 測內容盒,再把測量結果餵給插值;摺疊保持 0 或固定標題高度,於是兩端都是長度而非“長度+關鍵字”。

.panel[data-open="true"] .panel-body {
  height: calc-size(fit-content, size);
}
.panel[data-open="false"] .panel-body {
  height: 0;
}

從 max-height 遷移時對比主觀速度:calc-size() 跟隨真實內容深度,短答覆與長政策文本的 easing 都更誠實。缺點是動態內容敏感:過渡中 live region 插入文字會移動端點(行為正確,但若 easing 假設固定距離會被拉長)。靜態頁建議在 transitionend 前凍結 DOM,除非你明確支持中途迴流。

與 padding 同用時牢記 box-sizing:模板常寫 * { box-sizing: border-box; },確認測量高度覆蓋你期望的 border box,否則 Safari 可能只動畫內容高度而邊框單幀彈出。

用 @supports 漸進增強

分層回退:無 calc-size() 時仍可瞬時切換或 max-height 裁剪。特性查詢要測函數令牌本身,而非籠統屬性名,避免“能解析但不能插值”的半實現。

@supports (height: calc-size(fit-content, size)) {
  .panel-body { transition: height 240ms ease; }
}
@supports not (height: calc-size(fit-content, size)) {
  .panel-body { transition: max-height 320ms ease; max-height: 0; }
  .panel[data-open="true"] .panel-body { max-height: 80vh; }
}

構建時把 @supports 結果寫進 HTML 註釋便於支持團隊,但不要用現代 CSS 單獨門禁內容:無樣式用戶仍需標題與錨點。把動效視為語義 details/summary 或帶 aria-expanded 按鈕的可選增強。

Grid、flex 與 min-height:auto

flex 子項默認 min-height:auto,不會低於內容最小貢獻;從 0 動畫到內聯高度時常需 min-height:0 讓摺疊態誠實且無 overflow 噪聲。grid 同理:min-size:auto 與軌道尺寸會讓行拒絕收縮。

disclosure 放在 align-self:stretch 的網格區域時,塊級尺寸已確定,即便內容想內聯,也會影響 calc-size() 解析,可能比 flex 更快,也可能與 aspect-ratio 衝突。營銷頁正文傾向單列 grid,把動畫面板隔離到獨立格式化上下文,確認 contain:layout 不會裁切焦點環後再啟用。

同時動畫 gap 與高度會讓 Safari 每幀跑兩次關聯佈局,若兄弟還在動畫 margin-block-end 更糟。高度 tween 時保持兄弟 margin 靜止,再用 opacity 柔化入場。

Safari/WebKit 實現提示

主線程忙時 WebKit 會合並樣式更新,高度過渡可能跳變,即便 M3 亦然。靜態頁雖少阻塞腳本,第三方統計仍可卡頓:把標籤推遲到首屏之下或 idle。跨 macOS 升級窗口要對比穩定版 Safari 與 STP 並留存像素差分。

硬件加速並不會把 height 自動交給合成器,它仍驅動佈局。與 transform:translateY() 同開等於雙份 layout+paint,除非謹慎 will-change:transform 抬層。手勢裡二選一:要麼 transform 滑動,要麼高度揭示。

亞像素文字在展開時若 -webkit-font-smoothing 狀態不一致,會出現“閃字”其實是位圖緩存失效,摺疊/展開分支請保持字體設置一致。

性能:佈局抖動與合併

每次高度採樣都觸發幾何佈局,五塊面板同時展開成倍消耗。限制併發、輕微錯峰,或在離開視口後對非可見面板使用 content-visibility:auto(先驗證讀屏可達)。用 WebKit 時間軸觀察紫色 layout 條是否超幀。

若仍用 JS fallback,審查 ResizeObserver:在 CSS transition 期間同步讀佈局會形成反饋環;必要時 requestAnimationFrame 節流,並在 document.hidden 時跳過寫入。

無障礙與 prefers-reduced-motion

大區域運動可能誘發前庭不適。遇到 prefers-reduced-motion: reduce 時把時長壓到近乎零或改用輕微 opacity 提示,勿刪內容,保持 DOM 順序與焦點策略。

@media (prefers-reduced-motion: reduce) {
  .panel-body { transition: none !important; }
}

鍵盤用戶依賴穩定焦點環:動畫裁切 outline 時,用 overflow:clip 配內層可聚焦 padding,或把 outline 移到內層。讀屏應在屬性變更時同步聽到 aria-expanded,而非僅等動畫結束,除非 UX 明確要求延遲(通常不建議)。

靜態 HTML 摺疊模式

靜態導出推薦單容器類名 + 極簡 JS 寫入 data-open,或用原生 details 再用 CSS 鏡像。無 JS 時 details 自帶開關,歷史上動畫要靠 hack;interpolate-sizecalc-size() 讓語義與動效對齊。混用時確保只有一套規則擁有高度,否則互相打架。

CSS 分層:排版、佈局、動效依次疊加,避免營銷覆蓋層在上線日用 !important 關掉過渡。S3/CloudFront 無服務端開關,把動效集中在 motion.css?v= 便於緩存失效。

矩陣:何時動畫內聯高度

場景是否動畫內聯高度備註
法律長文摺疊calc-size 跟隨真實深度,少猜 max-height。
無限滾動卡片很少應虛擬化,否則滾動指標抖動。
模態框視情況進出優先 transform,高度留給內容迴流。
粘性導航揭示謹慎與 sticky 合成層交互,務必 Safari 實測。

編號 QA 清單

  1. 在 320/390/834 px 用最長本地化字符串驗證摺疊與展開高度。
  2. 在 macOS 輔助功能裡切換 prefers-reduced-motion,確認狀態仍可感知。
  3. 快速連開五塊面板,觀察基線 M2 上 CPU 與風扇曲線。
  4. 按生產環境啟用第三方腳本錄製 WebKit 時間軸。
  5. 在過渡中點檢查裁切容器內的焦點順序與可見性。
  6. 若發佈窗口跨越 macOS 升級,比較穩定版 Safari 與 STP。
  7. 調整 webfont preload 後複測內聯測量。
  8. 為深色模式與高對比度抓取像素差分。

常見問題

還能用 max-height 嗎?

可作回退,但支持 calc-size 時優先內聯方案,長文本時 timing 更誠實。

能替代滾動驅動動畫嗎?

不能;時間線不同,謹慎組合並實測交互。

width:auto 類似嗎?

思路相近,但水平方向文本回流更貴,需要剖析。

可信的靜態動效不靠死記語法,而靠與生產字體、擴展、縮放一致的 Safari 真機演練。MacHTML 租用的 Mac mini$16.9/天,可 7×24 對齊客戶設備,用 SSH 做像素快照、用 VNC 給設計評審。

在雲 Mac mini 上演練內聯高度動畫

在 Apple Silicon Safari 打開靜態包,分析“摺疊風暴”佈局,再在合併動效 token 前簽字。

在雲 Mac 上測 Safari 動效
約 $16.9/天