Safari 与 WebKit 新特性
What's new in Safari and WebKit
2025年6月9日
一句话判断
Safari 19 一口气补齐了 scroll-driven animations、anchor positioning 和 cross-document view transitions 这三个 CSS 大特性,终于不用再为这些写一堆 JavaScript polyfill 了。
这场 Session 讲了什么
这场 Session 按四个类别介绍了 Safari 近期(18.2 到 19)的大量 CSS 和媒体更新。
动画方面,scroll-driven animations 让你可以纯 CSS 把动画绑定到滚动进度,不再需要 JavaScript 监听 scroll 事件。两种时间线:scroll() 绑定到最近的滚动容器,view() 绑定到元素进出视口的过程。Cross-document view transitions 在 Safari 18.2 已经发布,只需一行 @view-transition { navigation: auto; } 就能让同源页面之间的导航拥有平滑过渡效果。
布局方面,anchor positioning 让一个元素可以锚定到另一个元素并根据视口自动调整位置,配合 popover API 使用堪称完美。视觉效果方面,background-clip: border-area 让边框也能用渐变或图片填充;shape() 函数替代 path() 创建响应式形状;text-wrap: pretty 优化排版的断行效果。媒体方面新增 SVG favicon 支持、HDR 图片支持(配合 dynamic-range-limit CSS 属性控制 SDR/HDR 混排效果),以及 Ogg Opus/Vorbis 音频格式支持。
值得深挖的点
Scroll-driven animations 的两种时间线模型
scroll() 时间线绑定到最近的滚动祖先,值域 0-100% 对应滚动条从头到尾。view() 时间线则绑定到元素在视口中的可见性——0% 是元素进入视口底部,100% 是元素完全离开视口顶部。配合 animation-range 属性,你可以精确控制动画在滚动过程中的起止点。
Session 中的课程网格动画是一个典型用例:方块从不同方向”组装”成网格。用 view() 时间线,把 animation-range 设为 0% 50%,意味着动画在元素进入视口时开始、到达视口中间时结束。这样用户有足够的阅读时间,方块不会在整页滚动过程中一直晃动。
这个设计的 trade-off 很明确:animation-range 设得太短,动画可能一闪而过用户没看到;设得太长,元素长时间处于运动状态影响可读性。Session 中建议动画在元素到达视口中间位置时就结束,这个经验值得参考。另外要注意 prefers-reduced-motion 媒体查询——即使是 scroll-driven animation 也需要考虑无障碍,特别是旋转、视差、缩放等容易引发眩晕的动画类型。
Anchor positioning 的两套 API
Anchor positioning 实际上有两套 API:position-area 和 anchor() 函数。position-area 把锚点周围的区域抽象为九宫格(左/中/右 × 上/中/下),用 bottom center 这样的关键字描述目标元素的位置。当空间不足时,position-try 属性可以定义备选位置,比如从 bottom span-right 切换到 bottom span-left,或者用 flip-inline 自动翻转。
anchor() 函数更底层,直接把目标元素的边缘对齐到锚点的边缘:top: anchor(bottom) 让目标的顶部对齐锚点的底部。对于需要精确偏移的场景(比如考虑 padding),anchor() 配合 calc() 更灵活。
WebKit 团队在标准制定过程中贡献了 position-area 这个更直观的 API。实际使用建议:简单场景用 position-area,需要动画或多锚点的复杂场景用 anchor() 函数。
代码片段
纯 CSS 实现滚动进度条,零 JavaScript:
.progress-bar {
position: fixed;
bottom: 0;
left: 0;
height: 4px;
background: linear-gradient(to right, #ff6b35, #ffd700);
transform-origin: left;
animation: grow linear both;
animation-timeline: scroll();
}
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
一行 CSS 实现同源页面之间的过渡效果:
@view-transition { navigation: auto; }
用 anchor positioning 把下拉菜单锚定到头像按钮下方,自动响应视口变化:
.profile-button { anchor-name: --profile; }
.profile-menu {
position: absolute;
position-anchor: --profile;
position-area: bottom span-right;
position-try: flip-inline;
}
最佳实践
建议对 scroll-driven animation 和 view transition 始终包裹 prefers-reduced-motion 媒体查询。Crossfade 是相对安全的动画类型,但滑动、旋转等效果应该在 reduced motion 模式下禁用。
优先使用 position-area 而不是手动计算位置,因为它是 WebKit 团队推动的标准化方案,浏览器兼容性更好。需要响应式布局时,用 position-try 的 flip-inline 或 flip-block 而不是写 JavaScript 检测空间。
避免在不需要响应式的场景使用 shape() 函数——如果你的形状不需要随视口缩放,path() 函数的语法更简单直接。
还有什么值得关注
- Safari 响应式设计模式回归了 viewport presets,可以从预设的设备尺寸中选择,支持一键旋转横竖屏。
- HDR 图片支持 AVIF 和 HEIC 格式,
dynamic-range-limit: constrained值可以让 HDR 和 SDR 内容和谐共存(后续版本支持)。 - 新增 Ogg Opus 和 Ogg Vorbis 音频格式支持,加上之前的支持,Safari 现在共支持 15 种媒体格式。WebM 也已支持 MediaRecorder API。