CSS3 之 transform 中 3d 效果实现

CSS3 中新增的一些还是相当强悍的,特别是在动画这方面,以前我们做动画基本都是用 JS 循环去实现,现在在 CSS3 中,我们直接用新增属性就能实现!短短几行代码,能获得远超 JS 的性能表现。今天我们就来探讨一下 CSS3 中关于 3D 动画的属性。

一、必不可少的perspective!

perspective的意思就是透视。很好理解,有没有这个参数,决定了你的3d转换效果是不是3d的,没有透视,谈何3d。

perspective定义的是视点距离显示器屏幕的距离。

当perspective的值取200px,意思是视点距离屏幕200px。当元素设置translateZ为100px时,相当于元素距离屏幕100px,那么从视点看到元素投影在屏幕上的大小就为原来的两倍!同理,当元素的translateZ值取-200px时,那么其在屏幕上的投影为原来的一半,我们看到的大小也为一半。

perspective的定义方式有两种,其中一种是设置父元素,另外一种是将其写在元素transform里,例如“transform: perspective(10px) translateZ(-10px)”。

其中设置父元素的方法针对的是整个舞台,其中所有的子元素公用一个视点;而写入transform里,则是把元素本身当成舞台进行3d转换。

二、perspective-origin的理解

其实和transform-origin一样,perspective-origin定义的是视点位置。正常情况下,translateZ会使元素相对于其中心点进行缩放,但如果加入“perspective-origin: 25% 70%”,其缩放中心就会发生变化。

三、transform-style: preserve-3d

preserve-3d,顾名思义,保持3d效果,就是讲当前元素的显示设置设为3D模式,其会影响子元素的相互遮盖。

四、backface-visibility

设置3d空间位置后面的元素可不可见,即遮不遮挡后面的元素。

五、实际应用(3D旋转相册)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8"/>
    <title>3D旋转相册</title>
    <style>
        /* 样式区 */
        ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        #platform {
            position: absolute;
            left: 50%;
            top: 50%;
            width: 220px;
            height: 220px;
            margin: -110px;
            perspective: 4000px;
        }

        #platform ul {
            transform-style: preserve-3d;
            animation: rotateY 16s linear infinite;
        }

        #platform ul li {
            position: absolute;
        }

        #platform ul li img {
            width: 220px;
            box-shadow: 0 0 12px #888;
        }

    </style>
</head>
<body>
<div id="platform">
    <ul>
        <li><img src="./static/images/1.jpg" alt=""/></li>
        <li><img src="./static/images/2.jpg" alt=""/></li>
        <li><img src="./static/images/3.jpg" alt=""/></li>
        <li><img src="./static/images/4.jpg" alt=""/></li>
        <li><img src="./static/images/5.jpg" alt=""/></li>
        <li><img src="./static/images/6.jpg" alt=""/></li>
    </ul>
</div>
<script>
    (function () {
        var li = document.getElementsByTagName("li");
        var width = li[0].offsetWidth;
        var angle = 360 / li.length;//计算旋转角(deg)
        var offset = (width / 2) / Math.tan(Math.PI / li.length) + 20;//计算每个展示位偏移距离
        //设置每个展示位的角度及其偏移量
        for (var i = 0; i < li.length; i++) {
            li[i].style.transform = "rotateY(" + angle * i + "deg) translateZ(" + offset + "px)";
            localto(i);
        }
        //点击快速旋转定位
        function localto(index) {
            li[index].onclick = function () {
                clearInterval(window.timer2);
                var ul = this.parentNode;
                var curA = a;
                var resultA = -angle * index;
                timer2 = setInterval(function () {
                    if (parseInt(curA) == parseInt(resultA)) {
                        clearInterval(timer2);
                        timer2 = null;
                    } else if (curA < resultA) {
                        if (Math.abs(curA - resultA) > 180) {
                            resultA -= 360;
                            curA -= 0.8;
                        } else {
                            curA += 0.8;
                        }
                    } else {
                        if (Math.abs(curA - resultA) > 180) {
                            resultA += 360;
                            curA += 0.8;
                        } else {
                            curA -= 0.8;
                        }
                    }
                    a = curA;
                    ul.style.transform = "rotateY(" + curA + "deg)";
                }, 10);

            }
        }

        var a = 0;
        //循环播放
        function play() {
            timer1 = setInterval(function () {
                if (!window.timer2) {
                    var ul = document.getElementsByTagName("ul")[0];
                    if (a <= -360) {
                        a = 0;
                    }
                    ul.style.transform = "rotateY(" + a + "deg)";
                    a -= 0.25;
                }
            }, 20);
        }

        //悬浮暂停
        document.getElementById("platform").onmouseover = function (e) {
            clearInterval(timer1);
        };
        //移开继续动画
        document.getElementById("platform").onmouseout = function (e) {
            play();
        }

        play();
    })()
</script>
</body>
</html>