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/天