使用 CSS 开发整页动画

Internet Explorer 9 中引入了对 CSS 2D 转换的支持。Internet Explorer 10 Developer Preview 增加了对 CSS 3D 转换CSS 动画的支持。凭借 GPU 的强大功能和常规 JavaScript 异步运行,这些 IE10 功能与传统的基于脚本的动画相比,提供了更高性能和更灵活的备选方式。

在先前的博文中,我们介绍了 CSS 3D 转换以及 CSS 动画和过渡。在本篇博文中,我们通过介绍“整页动画”的概念,来介绍上述技术的“非比寻常”的使用案例。在导航过程中,使用“整页动画”可以提高浏览的流畅性和持续性。我们的目标是实现无缝浏览体验,也就是当用户单击一个链接或执行相关操作来访问一个页面时,网页内容可以流畅地呈现。

可以通过使用 CSS 动画转换 HTML <body> 元素来实现上述效果。不过,该使用案例提供了一些我们认为值得讨论的注意事项,例如转换 <body> 上布局和尺寸的效果,以及如何恰当地设定页面导航所需时间,以便能与动画恰当地接合。

本篇博文中的代码示例使用未带前缀的 CSS 标记(IE10 Release Preview 提供支持);对于使用的 CSS 动画和 CSS 转换属性,其他浏览器可能需要供应商前缀。

转换页面的完整内容

CSS 转换是在 HTML DOM 元素的样式属性上定义的。例如,沿着 Z 轴旋转某个元素 45 度的标记类似如下:

#element {

transform: rotateZ(45deg);

}

将某个转换附加到您的 HTML 文档的<body>元素,方式也完全一样。所以要按顺序执行以便声明性地向 <body> 添加同样的效果,您可以执行以下类似代码:

body {

transform: rotateZ(45deg);

}

我们来看一下向主体元素应用转换之前和之后的页面屏幕截图:

该屏幕截图显示向文档的主体元素应用 rotateZ(45deg) 转换
向文档的主体元素应用 rotateZ(45deg) 转换。

对于三维转换,CSS 转换规范定义了可以针对我们要转换元素的父元素指定的 perspective 属性。当转换内容的 <body> 元素时,它将需要应用到 <html> 元素(在 DOM 层次结构上驻留在主体元素上)。这样做很直接:

html {

perspective: 500px;

}

<body> 元素上将此代码与 rotateY(45deg) 转换合并在一起,可以产生以下结果:

该屏幕截图显示将 rotateY(45deg) 转换应用到 <body>(其 perspective 在 <html> 上设置为 500px)。
该屏幕截图显示将 rotateY(45deg) 转换应用到 <body>(其 perspective 在 <html> 上设置为 500px)。

我们可以在主体元素上操控 transform-origin 属性,以获得自己想要的效果。让我们来看几个示例:

body {

transform-origin: 50% 100%;

transform: rotateX(45deg);

}

上面的标记对主体元素设置了一个沿 X 方向的旋转,同时使用 transform-origin 将旋转的原点移动到元素的底部。这样会有效地将文档的内容旋转成以下所示的屏幕:

该屏幕截图显示将 transform:rotateX(45deg) 和 transform-origin:50% 100% 应用到 <body> 后的效果

我们还可以对文档的根路径元素操控 perspective-origin 属性,以获得离轴投影效果。将 <html> 的样式更改为:

html {

perspective: 500px;

perspective-origin: 90% 50%;

}

现在页面会如下所示:

该屏幕截图显示将 perspective:500px 和 perspective-origin:90% 50% 应用到 <html> 元素后的效果

通过使用 CSS 转换,我们可以轻松地操控网页内容的整体视觉效果。由于常规的布局和尺寸规则仍然适用,所以主体元素上的某些转换(特别是使用百分比值或依赖 transform-origin 属性的那些转换)可以产生不同的视觉效果(取决于页面的内容)。现在再以先前将 transform-origin 设置为 50% 100%rotateX(45deg) 示例为例。

下面您可以看到应用转换前和应用转换后的结果。

该屏幕截图突出显示在透视投影下应用转换前和应用转换后滚动条的变化

请注意,内容实际上并不是以窗口底部为中心进行旋转,而是位于视口之外的某些点上。这是 CSS 转换的预期的行为:<body> 正常布置,然后它沿底边旋转,可能某些部分会旋转出屏幕。您还会注意到内容的实际印迹已经扩展(在应用转换“后”的屏幕截图上看一下滚动条),以便容纳转换后的内容(我们使用透视投影会令这个效果更加突出)。

因此,当我们向主体元素应用转换时应如何处理那些任意大小的内容?自定义剪裁所有内容以便确保主体的尺寸不会超过某个数值,这可能不太现实。反之,我们可以使用简单的 HTML/CSS 模式,允许我们将主体元素的大小调整为适合浏览器窗口,并将内容附加到包装 <div> 内。下面的标记会实现类似如下效果:

html, body {

width: 100%;

height: 100%;

min-width: 100%;

max-width: 100%;

padding: 0;

margin: 0;

overflow: hidden;

}

 

#Wrapper {

position: absolute;

width: 100%;

height: 100%;

overflow: scroll;

}

下图显示当一个页面垂直滚动,我们将 rotateY(45deg) 转换直接应用到文档的 <body> 元素(左)以及使用包装模式(右)后各自出现的情况:

该屏幕截图显示当一个页面垂直滚动,并且 rotateY(45deg) 转换应用到透视投影下的 <body> 元素,分别应用和不应用包装 CSS/HTML 模式的情况

直接应用转换会产生一个倾斜的视觉效果,这是因为离轴投影的原因(因为我们不再查看主体元素的“中心”)。使用包装模式可以确保 <html> 元素的 perspective-origin 属性(默认为50% 50%) 将始终正确地以 <body> 元素为参考设定中心,令视觉效果赏心悦目。

通过利用上面的模式,并尽可能地设置带有百分比值的 CSS 转换,我们可以以一致的方式影响 <body> 元素,不论内容的大小。

从转换到动画

厘清向 <body> 元素应用 CSS 转换的头绪后,下面来看 CSS 动画。通过遵循上面所述的原则,我们可以创建动画,可以将 Web 内容以生动有趣的方式呈现到视图中(或从视图中删除)。

现在以这个基本的 @keyframes 规则为例:

@keyframes rotateInLeft {

from {

transform-origin: 0% 0%;

transform: rotateY(180deg);

}

to {

transform-origin: 0% 0%;

transform: rotateY(0deg);

}

}

当应用到某个元素时,此动画会导致该元素绕其左侧旋转。当应用到一个使用包装模式的 <body> 元素时,视觉效果可能会更有意思。该文档会从浏览器窗口的可视区域外面旋转,直到旋转为完整视图:

三张屏幕截图依次显示应用“rotateInLeft”动画的效果

类似地,我们可以编写动画,将我们的 Web 内容流畅地从视图中删除。例如,如果我们希望页面在旋转的过程中逐渐从远处消失,可以使用类似编码:

@keyframes whirlOut {

to {

transform: scale(0)rotateZ(1260deg);

}

}

视觉效果变为:

三张屏幕截图依次显示应用“whirlOut”动画的效果

由于我们可以使用 CSS 动画的全部功能来影响所有 Web 内容,因此在生成这些页面效果时我们具有很强的灵活性(并且我们并不局限于仅使用 CSS 转换)。不过,如果编写出想要应用到内容的效果后,应如何在页面导航过程期间开始应用这些效果?

将动画附加到 <body>

我们的目标是在浏览器体验的关键时间点使用触发动画,以便在用户单击某个链接后页面加载视图或淡出该视图时,可以令内容过渡性地呈现在视图中。

要将动画添加到主体元素,第一个直观的位置应该是 onload JavaScript 事件。不过,当 onload 启动时添加动画实际上有点太晚了。当页面上的所有内容已经完成加载(包括所有图片或其他极其占用带宽的资源)后,此事件最终会触发。在一个极其占用带宽的页面上将动画附加到 onload,可能会导致页面显示“正常”,然后会触发动画,并且将该内容重新加载到视图中。这并不完全是我们追求的效果。

或者,我们可以利用 DOMContentLoaded 事件,当浏览器分析完内容的 DOM 结构后会触发该事件(但可能是在资源完成加载前)。IE Test Drive DOMContentLoaded 演示说明了上述两种事件之间的区别。不过,如果是复杂的 Web 内容,一个高级的浏览器可能选择执行“激进式”呈现,在完整的 DOM 树加载完之前显示页面。在这些情况下,视觉效果可能类似于 onload 情形。

设置动画以便将页面内容过渡性地加载到视图中的最佳位置是在 <body> 元素的顶部内联。这可以确保动画将在呈现内容时开始播放(内容的起始位置就是我们选择的动画的 from 关键帧的起始位置)。这种方法的一个好处就是动画可以实际掩盖在加载复杂内容时可能出现的任何激进式的呈现、重新布局或资源加载。

设置动画使我们的内容逐渐淡出视图,这也非常有趣。用户可以假设,我们可以将 onclick 处理程序附加到内容中所有感兴趣的元素(例如所有 <a> 标记),只需在回调函数中设置相关动画属性(animation-nameanimation-duration 等)。不过,如果我们并未实际推迟导航的发生,将不会看到我们期待的流畅过渡。

这是利用 CSS 动画规范中描述的动画事件的好机会。特别地,我们可以使用 animationend 事件检测动画何时完成并触发导航(例如,通过设置 window.location.href)。因此,我们的 onclick 将触发“从视图中删除”动画,并且为 <body>上的 animationend 注册一个处理程序,这将确保导航事件发生。

提供实时演示

我们已经创建了一个 演示和一个教程(英语),教程内容是有关如何令页面实时使用 CSS 转换和动画,提供了深度介绍以及一些未在本文中提供的示例。该教程本身在页面导航中利用了整页动画,可以 在 Windows 8 Internet Explorer 10 以及 Chrome 和 Firefox 的最新版本上运行。

要简单地享受页面到页面的动画,只需使用每个页面的右下角的“Continue to ...”(继续)链接来浏览整个教程的页面。

在教程的结尾,我们提供了一些额外的指导和示例代码,是有关如何将这些动画内容与您自己的 Web 内容合并。

总结

CSS 转换和 CSS 动画是两个强大的功能集,可以提供丰富的沉浸式 Web 体验。本博文概述了使用 CSS 转换和 CSS 动画完整呈现 Web 内容时的注意事项。只需很少的工作,您就可以创建 Web 页面(有可能是静止页面),提供一个流畅且类似于应用程序的导航体验。

—Internet Explorer 图形主管项目经理 Charilaos “Harris” Papadopoulos

Comments

  • Anonymous
    August 23, 2012
    很炫的网页制作功能 很想学啊