靜態導出的營銷頁依然大量摺疊面板、篩選抽屜與幫助說明,需要在零高度與自然內容高度之間順滑過渡,卻不想為每個斷點手寫像素表。多年裡業界只能回答“用 JavaScript 量 scrollHeight 再寫像素”,因為 height: auto 在計算值階段被視為不可插值的關鍵字。2026 年,interpolate-size: allow-keywords 與 calc-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 ease 在 0 與 auto 間切換,多數引擎在區間末尾直接跳變,因為缺少一對數字端點。於是出現 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,引擎才能把內聯關鍵字與長度之間的過渡視為可測量端點。寫作時通常放在 .disclosure 或 details 外層,而不是全局 body,否則無關規則也會被拖入更大的插值表面,成本意外上升。
.disclosure {
interpolate-size: allow-keywords;
overflow: clip;
transition: height 260ms cubic-bezier(.2,.8,.2,1);
}
與顯式 height 狀態配對:摺疊可為 0,展開仍可寫 auto,但引擎現在能走出數值軌跡。若用類名在 height:0 與 height: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-size 與 calc-size() 讓語義與動效對齊。混用時確保只有一套規則擁有高度,否則互相打架。
CSS 分層:排版、佈局、動效依次疊加,避免營銷覆蓋層在上線日用 !important 關掉過渡。S3/CloudFront 無服務端開關,把動效集中在 motion.css?v= 便於緩存失效。
矩陣:何時動畫內聯高度
| 場景 | 是否動畫內聯高度 | 備註 |
|---|---|---|
| 法律長文摺疊 | 是 | calc-size 跟隨真實深度,少猜 max-height。 |
| 無限滾動卡片 | 很少 | 應虛擬化,否則滾動指標抖動。 |
| 模態框 | 視情況 | 進出優先 transform,高度留給內容迴流。 |
| 粘性導航揭示 | 謹慎 | 與 sticky 合成層交互,務必 Safari 實測。 |
編號 QA 清單
- 在 320/390/834 px 用最長本地化字符串驗證摺疊與展開高度。
- 在 macOS 輔助功能裡切換 prefers-reduced-motion,確認狀態仍可感知。
- 快速連開五塊面板,觀察基線 M2 上 CPU 與風扇曲線。
- 按生產環境啟用第三方腳本錄製 WebKit 時間軸。
- 在過渡中點檢查裁切容器內的焦點順序與可見性。
- 若發佈窗口跨越 macOS 升級,比較穩定版 Safari 與 STP。
- 調整 webfont preload 後複測內聯測量。
- 為深色模式與高對比度抓取像素差分。
常見問題
還能用 max-height 嗎?
可作回退,但支持 calc-size 時優先內聯方案,長文本時 timing 更誠實。
能替代滾動驅動動畫嗎?
不能;時間線不同,謹慎組合並實測交互。
width:auto 類似嗎?
思路相近,但水平方向文本回流更貴,需要剖析。
可信的靜態動效不靠死記語法,而靠與生產字體、擴展、縮放一致的 Safari 真機演練。MacHTML 租用的 Mac mini 約 $16.9/天,可 7×24 對齊客戶設備,用 SSH 做像素快照、用 VNC 給設計評審。
在雲 Mac mini 上演練內聯高度動畫
在 Apple Silicon Safari 打開靜態包,分析“摺疊風暴”佈局,再在合併動效 token 前簽字。