一切从一条推特开始
上下文
所以我们都在同一页上,Hugo 的意思是,有两种不同的方式可以“移动”元素。
- 为元素设置
relative
、absolute
或fixed
定位。然后,您可以使用top
、right
、left
、bottom
(或任何组合)来移动物体。 - 确保元素具有
display
值为block
或inline-block
,然后使用 transform 值translate()
、translateX()
或translateY()
来移动元素。
“更好”,版本 1
我对这个语境下“更好”含义的第一个想法是,哪种方式在不同情况下更合适。这让我说:“不要将定位与设计动效混淆。”
举个例子。你有一个按钮。你想对这个按钮应用一个效果,让它在 :active
状态下向下移动 2 像素,模拟“按下”的效果。这是一种设计动效,应该用 translate()
来完成。你也可以用 top
或 bottom
和相对定位来实现,但这样就会混淆定位和设计动效的概念。
假设在应用程序的另一个地方,你绝对定位了一个按钮(完全合法)。现在,当 top: 2px;
被应用到按钮的 :active
状态时,这个按钮可能会飞到你意想不到的地方,可能导致按钮无法点击。
使用 translate()
将始终从元素的当前位置“推动”它,这对于这种效果,或者任何设计特定的动效来说都是完美的。
“更好”,版本 2
Hugo 更可能指的是性能。使用 translate()
来移动元素比使用 top/right/bottom/left 具有更好的性能,这已经成为一种通用的建议。但是,数据是否支持这种说法?让我们来看看。
首先,我做了一个非常简单的动画,一个红色球来回移动。
在我的肉眼看来,在最新稳定的 Chrome (23) 和装有 RAM 的 Retina MacBook Pro 上,translate()
版本确实略微表现更好。我可以看到 top/left 版本有非常轻微的卡顿。感知很重要,但让我们看看真实的数据。
在 Chrome 开发者工具中,您可以点击“Timeline”选项卡,然后点击“Frames”,然后按下底部的圆形“Record”按钮。在动画运行时,开始录制一小段时间,然后停止它。如果其他网站不可见,特别是如果它们正在进行任何动画,数据会更好。
在 top/left 版本中,您可以看到偶尔的峰值出现在标有“60 FPS”的线之上,即每秒六十帧。这是我们试图保持在下面的线,因为它相当于完美的平滑感知运动。


但是等等
这变得更加复杂。我开始与 Paul Irish 交谈,他是 Google Chrome 团队的成员。Paul 认为,由于这些“绘制”非常简单,这可能不是最佳的真实性能指标。Paul 采用了我的演示,并提高了复杂性。不是红色球,Josh Hibberts MacBook Pro。不是白色背景,Nate Eagle 的沙发布料。
当Paul 的例子显示出与我们预期相反的结果时,事情变得奇怪了。top/left 版本看起来比 translate()
版本更平滑。令人惊讶的是,“Frames”时间轴没有显示任何重大差异。
这就是 Paul 开始深入研究这个奇怪的世界的地方。他想出了很多有趣的东西!Paul 与 Chrome 团队中的另一位 Paul,Paul Lewis 交谈,他同意“使用 translate()
来进行设计动效更明智”。但接着说,这不仅仅是帧速率的问题。使用 translate()
,你可以获得亚像素动画,这是一种在像素之间模糊的效果,通常会导致更平滑的动画。
在亚像素 [动画] 中,你会失去清晰度,这是正确的。关键是在极值处保持更长的圆形值,这样你的眼睛就能获得清晰度的满足,同时获得运动的平滑性。
Paul Irish 深入挖掘
我会把这个交给 Paul。 他制作了一个 13 分钟的视频,你应该看看。它解释了所有这些花哨的 GPU 东西、亚像素渲染等等。
非常有趣。很棒的推特,Hugo!
感谢 Chris 和 Paul 抽时间来解决这个问题。
嘿 Chris,非常感谢你发表了这篇文章!你和 Paul 做了一份很棒的工作来涵盖这个主题。问题解决了!;)
很棒的推特,Hugo!
这是一次很好的体验,特别是观看 Paul 的屏幕截图。
你好,我在 Chrome 上尝试过,使用 translate 更平滑。很奇怪!
在 Webkit 中,过渡和动画几乎总是更平滑 :)
是的。对我来说,translate 更平滑。o.O
我在 Firefox 上也是一样的。
很棒的文章 Chris。
但是,前两个红色球链接指向同一个位置 :)
top/left 的正确链接:http://codepen.io/chriscoyier/pen/pBCax
抱歉,应该使用完整链接而不是笔链接:http://codepen.io/chriscoyier/full/pBCax
(真可惜我不能编辑我的第一条评论。这浪费了非常多的垂直像素。)
谢谢,已修复。由于这是一个临时问题,所以我会把它埋起来。
一直期待这个问题的答案。感谢你们二位的深入研究!
在 Safari 6 中,translate 版本比 top/left 版本平滑很多。
我同意。
在 iOS6 上,translate 也快得多。
是的,重要的是要查看所有其他浏览器在不同方法下的表现,包括桌面和移动设备。好消息是:它们在使用 translate 时表现都更好。
Firefox Nightly 20 也是一样的。
在 iPad 上的 Chrome 中,translate 版本比 top/left 版本流畅得多。
top/left 版本看起来很丑!
更改 top/left/right/bottom 会将 DOM 元素移动到窗口内。这意味着所有内容都会被重新计算和重绘(因为这些修改可能会改变其他元素的行为方式)。
使用 translate(),您不会触碰 DOM 或其行为方式。只是渲染方式。这是一个巨大的差异,解释了性能差异,然后也使事情以不同的方式运作。元素本身及其所有 CSS 会一起移动,而不是改变其 CSS 参数。
您可以使用 background-attachment: fixed,然后更改 top/left 值或更改 translateX() 值来查看这种差异。
因此,如果我没弄错的话,元素的可点击区域会随着 trbl 方法移动,但不会随着 translate 移动,对吗?
Andy,由于整个图层都移动了,我相信“可点击区域”确实移动了:http://jsfiddle.net/joshnh/pyagP/
你说得对。我发誓我在某个地方看到过一个演示,它在 :hover 上移动,而热点区域保持不动。. . . 肯定是什么别的东西。
而且,在这里使用 JSFiddle 而不是 CodePen 的人真是勇敢!:)
正如 CM 指出的,第一个演示链接更强大。
我也同意其他评论者的观点,对于重型演示,在 Chrome 中,translate 更流畅,这与您的文章的建议相反。
strong = wrong* :P
一如既往,非常有趣的阅读!谢谢!
这感觉像一个愚蠢的问题,但是,两种方法的浏览器兼容性有区别吗?或者在编写浏览器兼容的 CSS 方面有什么区别?(哪一种更兼容,哪一种更适合用更少的 CSS 解决方法进行简单的编码等?)
当 Paul 的示例显示出与我们预期的相反结果时,情况变得很奇怪。top/left 版本看起来比 translate() 版本更流畅。—在 Win7 x64 上的 Firefox 17.0.1 中,
translate()
看起来比top/left
流畅得多,但仅在对象第一次移动后才会如此。对象第一次移动时,看起来确实很卡顿。很微妙,但看到你的示例中的差异真的很有趣,现在我知道当事情看起来不太对时,尝试两种方法都是值得的。
这太棒了!我一直都是使用 top/left/bottom/right 来做一些类似滑动菜单之类的事情,因为 translate 在 IE8 中不受支持,而且我不想编写额外的 CSS。但是,这明确地证明了使用 translate 是值得额外努力的。记住了。
使用 IE10,translate() 看起来非常流畅,而另一个则非常卡顿,有 10 个 MBP。球看起来是一样的。即使只有一个 MBP,top/left 也是有点卡顿。
所以我的答案最终证明是正确的。很好!
我注意到 SwipeJS 库 在智能手机上使用
translate
进行 1:1 的滑动和动画。我很想知道作者为什么要使用 translate,所以我用负边距替换了它,然后用position:relative
进行比较。差异很大,所以我很快又切换回translate
。在移动客户端上,由于计算能力有限,这将决定动画是卡顿还是流畅。我听说为了激活 iPhone 的硬件加速,你需要使用 translate…
我发现使用 jQuery slideDown/slideUp 制作一个简单的下拉菜单时,这是真的。. . . 在 iPhone 上它很卡顿。. . . 但是当我切换到只是切换类并使用过渡和 translate 时,性能要好得多。. . .
我很好奇 translate3d 的表现如何。我在我的 Liquid Slider 中使用 translate3d,因为我认为它可以提升性能,尤其是在 iOS 设备上。这仍然准确吗?
感谢你们两位发布了这篇文章。在一些我自己的动画中使用 Chrome 开发者工具进行测试真是太好了。继续努力!
在这里,在 FF17 上,translate() 好得多,尤其是在我点击“添加 10 台更多 MacBook”时。
使用 top/left,动画非常卡顿,子元素(如打开)的盖子不会与 MacBook 的其他部分一起移动。
我的天啊。
我也看了 Paul 的视频,真是太棒了。之前做过一个项目,它在 left/right 动画方面非常重,可能需要回去更新一下。
非常好的文章。感谢分享!
很棒的推文和帖子!
讨论很好,可以扩展到其他浏览器,比如 Firefox 或 Opera,以便获得良好的 C
有趣的是,在 Ubuntu 的 Firefox 上,对于红色球的版本,top/left 稍微流畅一些。对于 MacBook 示例,translate 流畅得多。
这证明了为什么每周多次访问 css-tricks/Coyierland 是必须的。他们用科学的方法解决了每一个细微的网络问题,一次又一次地深入挖掘准确的信息。它是 www 上始终如一地最好的信息资源之一。细微但有趣的问题,出色的链接和回复,用于高级知识。再次致敬。
有人提到我的名字了吗?
我很高兴我超级复杂的径向渐变终于为人类服务了。
我知道我来晚了一点,但我想你们可能会觉得这很有趣。. . .
我发现当更多元素进行动画时,top/left 在大多数浏览器中快得多。请查看 http://www.greensock.com/js/speed.html 中的比较。在承受巨大压力的情况下,translate() 技术慢了 400%(甚至更多)。唯一的例外是 iOS Safari。很奇怪。
因此,我认为您在 translate() 中看到的性能提升仅适用于某些情况,例如当少数元素同时进行动画时,或者它们使用不透明度、盒阴影等效果。但是,存在一个阈值,在这个阈值下,“硬件加速”的优势实际上会成为一个重大的瓶颈(感谢 Paul Lewis 指出这一点)。再说一次,如果您没有对很多元素进行动画,则子像素渲染可能很好。
精彩的讨论,伙计们。
补充一下我的发现:最新的 Chrome(23.0.1271.97)在使用 translate() 和 1 台 MacBook 的复杂示例中看起来流畅得多,但最奇怪的是,当添加更多 MacBook 图片时,性能不会下降,而 top/left 的性能却呈指数级下降!一定发生了一些我无法理解的超级棒的优化。
不错的帖子,我发现最新版本的 FF 和 Chrome 流畅得多,但事实仍然是我们想要使用许多不错的 CSS3 效果,但用户在项目中阻止了这一点。. . . 作为开发者,最终你必须创建一个对用户群来说尽可能可用的网站。
Muy Interesante me gusto :D
如果你使用这种方法来动画化包含表单元素的面板(Firefox 漏洞),请小心:当这些元素获得焦点(或在文本输入框中输入文本)时,面板将独立于你用来检测或重新定位面板的任何值移动(并且这些值将不同步)。这很烦人。在 Mozilla 的某个地方有一个错误报告。
在 MacBook 的示例中,translate 非常流畅,而 top/left 在 Firefox 和 Chrome 中对我来说都很卡顿。你怎么说 top/left 更流畅呢?