IE9 及其以下版本完全不支持 CSS 3D transforms 技术, Opera 12 也不支持. 具体支持信息请查看 http://caniuse.com/#feat=transforms3d .
CSS 动画是当前一种非常火爆的技术, 我说的并不是一些简单的颜色变换或长短属性变换, 我说的是 3D 变换技术; 纯 CSS 实现的翻滚旋转立方体就是最典型的例子. 网上能找到很多关于 CSS 动画的代码, 但对于一个程序员来说, 真正理解其为什么会动起来的原理是非常重要的. 下面让我来一步一步的带你理解网页中相互嵌套的 3D 动画是如何实现的!
假设我们在一个门框内有一扇门:
html 代码非常简单:
- <div class='container'>
- <div class='frame'>
- <div class='door'></div>
- </div>
- </div>
为了打开这扇门, 我们给它添加一个 door--opencss 类:
- <div class='container'>
- <div class='frame'>
- <div class='door door--open'></div>
- </div>
- </div>
现在, 我们对它使用 3D 变换技术 (通过对它的左侧应用) 属性:
- .door--open {
- transform-origin: 0 0 /*whatever y value you wish*/;
- transform: rotateY(-45deg);
- }
对于使用 CSS 3D 变换, 你唯一需要添加的 CSS 前缀可能只有 - webkit-.IE9 是完全不支持的, 但 IE10 + 是不需要使用前缀的. Opera 12 及其之前版本完全不支持 CSS 变换技术, 之后的版本在使用 - webkit - 前缀后是支持的. 火狐浏览器从 V16 版 (2012 年) 起不需要使用前缀.
效果:
现在的效果看起来并不是很真实. 更真实实现这种效果的 CSS 属性叫做 perspective(透视), 它会让东西看起来近处的大, 远处的小.
perspective 属性必须应用到需要做 3D 变换的元素的父元素上. 在 WebKit 浏览器里, 只要是它的祖先元素都行, 但在火狐或 IE 里只能是父元素.
现在我们要往门框元素上添加一个 frame--realistic 类:
- <div class='container'>
- <div class='frame frame--realistic'>
- <div class='door door--open'></div>
- </div>
- </div>
现在我们在其上设置 perspective 透视属性. 透视属性的值约小, 它就会显得离你的眼睛越近, 这样, 越近的东西会显得越大, 越远的越小.
- .frame--realistic {
- perspective: 20em;
- }
我们就得到了下面的效果:
这样看起来就好多了! 但我们可以做得更好! 比如, 我们可以让这扇门动起来, 并且具有 3D 效果. 我们只需要在 HTML 和 CSS 里将 door-open 类换成 door--ani 类:
- .door--ani {
- transform-origin: 0 0;
- animation: doorani 1.3s ease-in-out infinite alternate;
- }
- @keyframes doorani {
- from { transform: rotateY(-43deg); }
- to { transform: rotateY(43deg); }
- }
效果:
现在, 我们还想让这扇门的门框也以 3D 的形式动起来. 这很简单, 不是吗? 只需要在门框上添加一个 frame--ani 类, 设定一个动画动作, 将 perspective 透视属性移动到它的父元素上:
HTML 代码变成了这样:
- <div class='container container--realistic'>
- <div class='frame frame--ani'>
- <div class='door door--ani'></div>
- </div>
- </div>
我们还需要添加下面的 CSS 代码:
- .container--realistic {
- perspective: 20em;
- }
- .frame--ani {
- animation: frameani 2s ease-in-out infinite alternate;
- }
- @keyframes frameani {
- from { transform: rotateY(-30deg); }
- to { transform: rotateY(30deg); }
- }
可是, 我们得到的效果却是:
看起来有些怪. 看起来门的动画效果被门框的摆动抵消了. 的确, 事情就是这样, 因为属性 (用来告诉浏览器一个具有 3D 变换属性的子元素是否附随父元素的 3D 变换属性) 的缺省值是 flat.
这个问题可以通过将其父元素设置 transform-style: preserve-3d 来纠正. 这样, 我们就可以看到更自然的效果了:
但是, IE10/11 只支持 transform-style 的 flat 值. 有时我们会利用这种技术将父元素和子元素通过 3D 变换串联起来.
例如, 我有一个稍微倾斜的立方体(没有顶部和底部面).HTML 代码是:
- <div class='container container--realistic'>
- <div class='cube'>
- <div class='face'></div>
- <div class='face'></div>
- <div class='face'></div>
- <div class='face'></div>
- </div>
- </div>
相关的 CSS:
- .cube {
- position: relative;
- width: 5em; height: 5em;
- transform-style: preserve-3d;
- transform: rotateY(30deg) rotateX(10deg);
- }
- .face {
- position: absolute;
- width: 100%; height: 100%;
- }
- .face:nth-child(1) {
- transform: /*rotateY(0deg)*/ translateZ(2.5em /* half the side length, 5em in this case */);
- }
- .face:nth-child(2) {
- transform: rotateY( 90deg) translateZ(2.5em);
- }
- .face:nth-child(3) {
- transform: rotateY(180deg) translateZ(2.5em);
- }
- .face:nth-child(4) {
- transform: rotateY(270deg) translateZ(2.5em);
- }
使用这些代码(这里有更详细的解释), 我们得到了下面的效果:
如果你使用的是 IE, 我们需要在对每个面实施 3D 变换前先清空变换属性(如果这个立方体的父类也有变换特征, 也需要先清空.). 我将立方体的父元素也处理了, 就像下面:
- .cube--IE {
- perspective: 20em;
- transform: none;
- }
- .face--IE:nth-child(1) {
- transform: rotateY(30deg) rotateX(10deg)
- translateZ(2.5em);
- }
- .face--IE:nth-child(2) {
- transform: rotateY(30deg) rotateX(10deg)
- rotateY( 90deg) translateZ(2.5em);
- }
- .face--IE:nth-child(3) {
- transform: rotateY(30deg) rotateX(10deg)
- rotateY(180deg) translateZ(2.5em);
- }
- .face--IE:nth-child(4) {
- transform: rotateY(30deg) rotateX(10deg)
- rotateY(270deg) translateZ(2.5em);
- }
于是, 在 IE 里也得到了同样的效果:
虽然不是很方便, 但也不是很糟. 代码不是很多, 也不是很乱... 然而, 当我们想旋转这个立方体时却出现了问题. 我们需要使用 transform-style: preserve-3d 属性, 我们简单的增加了一个 cube--ani 类, 这段 CSS 代码是:
- .cube--ani {
- animation: rot 4s linear infinite;
- }
- @keyframes rot {
- to { transform: rotateY(-330deg) rotateX(370deg); }
- }
可是, 对于 IE10/11 来说, 我们无法对立方体自身施加 3D 变换, 我们只能对每个面单独实施 3D 变换. 这就是说, 我们要对所有的面设置变换属性. 这就是说.... 每个面都要!
- .cube--IE {
- animation: none;
- }
- .cube--ani .face--IE:nth-child(1) {
- animation: rot1 4s linear infinite;
- }
- @keyframes rot1 {
- to {
- transform: rotateY(-330deg) rotateX(370deg)
- translateZ(2.5em);
- }
- }
- .cube--ani .face--IE:nth-child(2) {
- animation: rot2 4s linear infinite;
- }
- @keyframes rot2 {
- to {
- transform: rotateY(-330deg) rotateX(370deg)
- rotateY(90deg) translateZ(2.5em);
- }
- }
- .cube--ani .face--IE:nth-child(3) {
- animation: rot3 4s linear infinite;
- }
- @keyframes rot3 {
- to {
- transform: rotateY(-330deg) rotateX(370deg)
- rotateY(180deg) translateZ(2.5em);
- }
- }
- .cube--ani .face--IE:nth-child(4) {
- animation: rot4 4s linear infinite;
- }
- @keyframes rot4 {
- to {
- transform: rotateY(-330deg) rotateX(370deg)
- rotateY(270deg) translateZ(2.5em);
- }
- }
这一大片, 就是为了实现这个效果:
如果这么多的代码只是为了这 4 个面, 那当需要面对 100 多个面 http://codepen.io/thebabydino/pen/nyjKz 时, 你能想象是多恐怖的一堆代码吗?
你也许会想到上面的门也有这种问题, 门的父元素有高度和宽度, 是可见. 如何在 IE 里实现? 唯一能让门和门框在 IE 里一起动起来的方案就是修改 HTML 代码, 让门和门框变成兄弟元素, 单独对它们施加动画效果.
(英文: How Nesting 3D Transformed Elements Works.)
来源: http://www.webhek.com/post/3d-transforms.html