视口外的视图转换
CSS View Transitions 已登陆 Chrome,并且(无论好坏)现在已广泛可供大多数终端用户使用。Safari 紧随其后,TP 中已提供该功能,Firefox 至少正在开发该功能。
我喜欢多页转换的实现变得越来越简单,但与此同时,我也意识到了它们的一个很大的缺点:视口之外的元素开始疯狂地移动。
我的博客使用一些 Javascript 来处理这个问题。`IntersectionObserver` 在可见时将 `view-transition-name` 设置为自定义属性。只要它不在视线范围内,该属性就未设置,转换也不会触发。它可以工作,但它需要 HTML、Javascript 和 CSS 相互依赖。本着将演示问题留给 CSS 的精神,我想要一个更简单的解决方案。
Chrome 最近推出了另一个可能有所帮助的功能:滚动驱动动画。遗憾的是,此功能目前仅在 Chrome 中可用。Firefox 已将其标记为启用,而 Safari 则没有活动迹象。但我们可以优雅地回退,要么使用之前提到的 Javascript 解决方案,要么干脆忽略视口检测并显示动画(在撰写本文时,Safari 就是这种情况)。
简单的过渡
让我们把它们放在一起,从视图转换本身开始:
@media (prefers-reduced-motion: no-preference) { @view-transition { navigation: auto; } [data-view-transition] { view-transition-name: var(--view-transition-name, default-view-transition); } }
Whoosh!Whoosh!
现在,您将看到导航时“page1.html”中的“div”转换为“page2.html”上的版本。CSS 中的“@view-transition”规则也会在整个文档上启动交叉淡入淡出。过渡持续时间默认设置为“0.4 秒”,但我们可以添加几行来控制它:
@property --view-transition-duration { syntax: "
持续时间由 `--view-transition-duration` 设置,顶部的 `@property` 规则完全是可选的,但当我们设置 `--view-transition-duration: bogus` 时,它可以让 `animation-duration` 回落到 `0.4s` 而不是无效值。
处理视口
尽管如此,当页面转换时元素位于视口之外时,它仍会进行动画处理,有时会进入或越过整个可见屏幕,而不会指示它来自哪里或要去哪里。我发现这种行为非常令人恼火。
有了滚动驱动动画,我们现在有了一个可以根据滚动和视口相对位置控制样式的工具。因此,我们还可以控制视图转换的触发器:
@property --view-transition-duration { syntax: "
`enable-vt` 关键帧动画无法从 `none` 平滑过渡到带有文本字符串的自定义属性,因此它会进行硬切换。`animation-range` 会在元素进入或离开视口时触发,即使只是部分进入或离开视口。动画本身将 `--enable-view-transition` 设置为 0.1% 和 99.9%,以尽可能迅速地触发。我希望在我们可以了解动画开始或结束的位置后立即启用视图转换。
最后,滚动驱动动画将 `--enable-view-transitions` 设置为 `none` 或名为 `--view-transition-name` 的新自定义属性。它被设置为屏幕覆盖率的 0.1% 到 99.9% 之间,禁用视口上方和下方(或左侧和右侧,无论您想以何种方式保持)的视图转换。此新属性可用于在不同元素上设置单独的动画。每个元素都可以通过为 `--view-transition-name` 设置一个唯一值来获得自己的转换。
Whoosh
这需要在源页面和目标页面上完成。如果未设置任何值,则默认为 `default-view-transition`,它将统一控制所有剩余的 `data-view-transition` 元素。
实际实施
我将此实现添加到我的小型 CSS 样板 Ssstyles 中。在源页面和目标页面上为元素提供 `data-view-transition` 属性将使其在两者之间过渡。为其提供 `--view-transition-name` 将使其拥有自己独特的动画,独立于其他类似元素。设置 `--view-transition-duration` 可控制过渡的持续时间。