CSS 动画(以及一些 JavaScript 技巧)可以让我们添加页面过渡,并摆脱页面加载的硬切。我的 jQuery 插件 smoothState.js 有助于完善这些过渡并提高 UI 响应时间。
页面过渡有益于用户体验
想象一下,如果你触碰门把手,就会被传送到门的另一边,那会是多么令人迷失方向。浏览网页的感觉就像使用传送门把手一样。布局会改变,元素会重新排列或消失,用户需要时间来适应。平滑的过渡减少了用户在新的环境中安顿下来的努力。
原生应用程序了解动画的重要性。很少有应用程序没有页面过渡,用户也已经习惯了这种更高水平的可用性。由于这种预期变化,网络开始感觉过时了。许多人认为网络体验不如应用程序。幸运的是,情况不必如此。
使用 CSS @keyframes 动画添加页面过渡
让我们看一个例子,看看如何开始添加页面过渡。在我们的演示布局中,我们可以看到网页典型的白色闪烁和硬切。

CSS 动画允许我们定义元素在页面上呈现时的视觉行为。要向我们的网站添加动画,我们应该
- 识别页面上的元素将如何动画
- 创建我们需要的关键帧
- 编写 CSS 声明
- 向布局添加类
识别页面上的元素将如何动画
让我们看看我们的示例页面

如果我们检查布局,可以找到一些添加过渡的机会。Google 关于有意义的过渡的指南是一套很好的元素动画规则。如果您是交互设计新手,可以从这里开始。
创建我们需要的 @keyframes
看起来我们需要三种类型的独特动画。
- 一个用于标题和按钮的淡入动画
- 一个带有轻微淡入效果的向上滑动动画,用于主页的内容
- 一个带有轻微淡入效果的从右侧滑入动画,用于详情页的内容
让我们创建这些 CSS @keyframes
并为它们命名
/*
* Keyframes
*/
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeInUp {
0% {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
100% {
opacity: 1;
transform: none;
}
}
@keyframes fadeInRight {
0% {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
100% {
opacity: 1;
transform: none;
}
}
}
编写 CSS 声明
现在我们有了关键帧,我们需要使用 CSS 动画属性将它们附加到类。以下是 CSS 代码:
/*
* CSS Page Transitions
* Don't forget to add vendor prefixes!
*/
.m-scene {
/** Basic styles for an animated element */
.scene_element {
animation-duration: 0.25s;
transition-timing-function: ease-in;
animation-fill-mode: both;
}
/** An element that fades in */
.scene_element--fadein {
animation-name: fadeIn;
}
/** An element that fades in and slides up */
.scene_element--fadeinup {
animation-name: fadeInUp;
}
/** An element that fades in and slides from the right */
.scene_element--fadeinright {
animation-name: fadeInRight;
}
}
重要的是要注意,动画时间过长会让用户感到厌烦。关于响应时间可用性的研究有很多。为了让 UI 感觉敏捷,请将动画持续时间限制在0.25 秒。进行一些快速粗略的用户测试,以确保您的动画不会让人感到厌烦。
向布局添加类
现在我们已经编写了 CSS,是时候将类添加到标记中了。
<!-- Home page -->
<div class="m-scene" id="main">
<div class="m-header scene_element scene_element--fadein">
...
</div>
<div class="m-page scene_element scene_element--fadeinup">
...
</div>
</div>
<!-- Detail page -->
<div class="m-scene" id="main">
<div class="m-aside scene_element scene_element--fadein">
...
</div>
<div class="m-right-panel m-page scene_element scene_element--fadeinright">
...
</div>
</div>
我们的结果是更美观的页面入口

我们仅仅使用 CSS 就对页面进行了一些改进。但是,即使有了这些改进,我们仍然看到闪烁,而且动画不像它们可以的那样紧凑。现在,我们将使用 smoothState.js 来解决这个问题。
使用 smoothState.js 添加光彩
smoothState.js 是一个 jQuery 插件,它逐步增强页面加载,使我们能够更好地控制页面过渡。要将它包含到我们的页面中,我们需要
- 获取 jQuery 的副本并将其添加到我们的页面中
- 下载 smoothState.js 并将其添加到 jQuery 之后。
- 创建一个新 .js 文件并将其包含在 smoothState.js 之后,我们可以在其中运行该插件。(或者使用您用于执行所有此操作的构建工具/连接过程。)
在我们的新 .js 文件中,我们希望使用 id 初始化 smoothState 到一个容器中。该容器应该包含页面上的所有内容。
;(function ($) {
'use strict';
var content = $('#main').smoothState({
// onStart runs as soon as link has been activated
onStart : {
// Set the duration of our animation
duration: 250,
// Alterations to the page
render: function () {
// Quickly toggles a class and restarts css animations
content.toggleAnimationClass('is-exiting');
}
}
}).data('smoothState'); // makes public methods available
})(jQuery);
smoothState 为我们提供了一个 onStart.render()
回调,它允许我们编排元素退出页面的方式。我们可以在显示新内容之前反转布局动画,从而消除页面的硬切。要执行此操作,请运行 .toggleAnimationClass()
函数,将类作为第一个参数传递。现在,我们将使用该类声明一个新的动画方向。
/*
* CSS Page Transitions
* Don't forget to add vendor prefixes!
*/
.m-scene {
.scene_element {
animation-duration: 0.25s;
transition-timing-function: ease-in;
animation-fill-mode: both;
}
.scene_element--fadein {
animation-name: fadeIn;
}
.scene_element--fadeinup {
animation-name: fadeInUp;
}
.scene_element--fadeinright {
animation-name: fadeInRight;
}
/** Reverse "exit" animations */
&.is-exiting {
.scene_element {
animation-direction: alternate-reverse;
}
}
}
我们还希望将用户动画回页面顶部。通过使用 jQuery 的 .animate()
函数并将 scrollTop
属性设置为 0
来实现这一点。
;(function ($) {
'use strict';
var $body = $('html, body'), // Define jQuery collection
content = $('#main').smoothState({
onStart : {
duration: 250,
render: function () {
content.toggleAnimationClass('is-exiting');
// Scroll user to the top
$body.animate({ 'scrollTop': 0 });
}
}
}).data('smoothState');
})(jQuery);
最终的结果是网站页面之间的平滑过渡。元素优雅地进入和退出页面,白色闪烁消失了。我们甚至在内容加载之前就触发了动画,因此用户会看到页面立即响应。

感谢这篇文章。我一直都在为 CSS 苦苦挣扎。但这篇文章绝对会帮助我。再次感谢!:)
我几乎要写类似的内容了——幸好我没有,因为我 JavaScript 不行。
我以前尝试过一个简陋的自制版本,方法是
preventDefault
do-page-leave-animations
,这会触发一些@keyframe
内容setTimeout
,其长度与这些动画的长度相同window.location
设置为被点击链接的href
do-page-enter-animations
,这会触发一些@keyframe
内容问题是……如果页面上有许多链接,我们不能预加载所有这些链接,否则会降低用户体验,对吧?
我一直都是用 AngularJS 路由和 HTTP 拦截来做这个……效果很好
我想看看您使用 Angular 路由和拦截器实现类似效果的方法……
我也想看看用 Angular 做的这个东西
也许我在这里遗漏了什么,但这种行为用 Angular 实现起来相当简单。我过去曾这样实现过:http://scotch.io/tutorials/javascript/animating-angularjs-apps-ngview
嘿!我有一些问题。
在
keyframes
代码中,为什么使用translate3d
而不是translate
?在 jQuery 代码中,为什么在创建立即执行函数之前使用分号?这是一种模式还是什么?
使用 translate3D 是为了使用 GPU。分号可能在这里是为了防止之前加载的脚本中忘记分号。
很棒的文章!我认为这在使用浏览器后退按钮时不起作用,但仍然是一个很好的简单过渡,不会破坏网页。在我们公司,我们发现自己在页面过渡中使用历史记录 API,因为客户不喜欢硬刷新,但仍然想要“真实”页面以提高搜索引擎友好性……所以,是的,我绝对会使用它。可访问性方面是实施它的一个很好的理由,尽管……从未这样想过……
很好!
在 iPhone 上测试,点击后退按钮似乎可以工作
继续努力!
需要什么最低版本的 jquery?我尝试在 Drupal 7 安装中实现它,但它没有添加动画类。
1.9 是基本要求。我没有做研究来查看它是否与更早的版本兼容,但它可能是。如果您在尝试实现 smoothState 时遇到任何问题,请随时与我联系。
哦,等等,重新初始化 javascript 也存在同样的问题……可能是因为它使用了历史记录 API………….
你有没有找到重新初始化 JS 的解决方案?我也遇到了同样的问题。
代码按原样工作吗?还是我们需要修改它?
这是一篇很棒的文章。它让我想起了 90 年代,当时 FrontPage 有页面过渡,除了这些过渡没有让我想要结束生命。
感谢您提供的另一篇精彩文章!
如果存在真实的页面重新加载,那将是一篇完美的文章。否则,这样做没有问题。如果您想使用真实的重定向进行淡入/淡出怎么办。不是 ajax 内容加载。我还没找到方法。
它运行完美且超级快!我有一个问题,我的一些页面使用 jquery 函数,在页面切换后它们就不再起作用了。如何重新初始化它们?
我遇到了同样的问题。
有人找到解决方案了吗?
我喜欢它。真的很棒。
绝对很酷的文章,但我质疑这是否真的对用户体验有好处。我理解从一个房间到另一个房间的瞬移的概念,但除非你预加载整个网站,否则你可能会为了过渡而阻塞导航。
嘿 Joe,感谢你的想法。
你能详细说明一下你所说的“阻塞导航”是什么意思吗?
很棒的文章!
啊,为什么这在 Chrome 上不起作用?
在我的 Windows 平板电脑上,第一次过渡到页面需要超过十秒钟。
使用 css3 背景动画测试过……它运行得像它的名字一样流畅,但是一些 jQuery 函数(比如简单的倒计时)在您导航到其他页面并返回到包含 js 函数的页面后就不起作用了。有人找到了解决此问题的办法吗?