zoukankan      html  css  js  c++  java
  • 吃透css3之3d属性--perspective和transform

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p

      写在前面:最近写了个3d轮播效果图,在此将思路和过程中遇到的问题都记录下来。


    首先,我们下来了解一下perspective和transform都是做什么的。

        transform -- css3属性,可以对元素进行变换(2d/3d),包括平移translate,旋转rotate,缩放scale,等等(完整取值参考 W3C)。

        perspective -- css3属性,当元素涉及3d变换时,perspective可以定义我们眼睛看到的3d立体效果,即空间感。通俗地解释就比如你去电影院看电影,你距离大荧幕的距离就相当于perspective的值啦,离得越远则perspective值越大,看到空间效果也就会不一样! 

    接下来,我们就进入正题了。

        先上3d轮播图效果图:

       

                      图一

       

                        图二

                     

           

                       图三

      ***图一为前一张轮播图,图二是轮播图前后切换时的3d效果图,图三为后一张轮播图***

    实现上面的效果,需要三层页面结构:

      1. 最外面的容器.swiper-wrapper,即图中天蓝色边框这个部分。为这部分设置关键css如下:

        transform-style: preserve-3d; //3d旋转效果
        perspective: 1000px; //3d立体空间感
        perspective-origin: 50% 50%; //观察视角, 50% 50%代表从中间观察

      2. 用ul包裹的li多边体。参考图二可知,我们的每张图片实际上是由n个片段拼接而成,这是怎么实现的呢?很简单,多个li + background-position定位轻松实现啦;

      3. li里的div数组,数组的长度等于轮播图的总张数。这个div数组将所有的图片围绕x轴形成了一个多边体。完整多边体效果如图四:

            

                                    图四

      那么怎么实现这个多边体呢?这就要用到今天的transform属性了。假设一个多边体有m条边,每个div平面代表一条边(即每张图片的1/n),我们先将每个div平面绝对定位到li的左上角(left:0;top:0;),此时的每个div平面都在x轴与y轴形成的平面上,也就是电脑屏幕平面上。接下来我们将每个div平面依次进行变换transform: rotateX((360/m)*i deg) translateZ(z轴位移量),先围绕x轴依次旋转(默认旋转点是平面中心,可以通过transform-origin设置,我们就是用默认值)(360/m)*0、 (360/m)*1 、(360/m)*2 、... 、直到(360/m)*(m-1),这样形成的下面的效果,图五:

            

                            图五

      咦?不是多边体么?别急,接下里translateZ(z轴位移量)登场了,这个值是多少自己拿小本本算去... 反正是每个边到中心点的垂直距离... ok, 看一下每个边平移后的效果吧,图六:

              

                             图六

      怎么超前的几个面变这么大了?都超出粉色的框框了... 没错,这就是平移translateZ产生的效果,立体地看,就是前面的几个面都跑到电脑屏幕外面了,后面的几个面跑到电脑屏幕后面了。还不明白?就是说电脑屏幕沿着这个多边形的中点,并且从多边形的垂直方向穿透过去了。还不明白的话我也没辙了...闭眼想像去吧...

      (tips: 以面对电脑屏幕的视角看,假设一个平面在屏幕上,则向右为其x轴正向,向下为其y轴正向,向屏幕外为其z轴正向。且当这个平面旋转时,他的3个轴也跟着旋转。)

      那怎么让最外面的图片放到电脑屏幕的平面上呢?聪明的人都知道了,把li代表的多边形整体translateZ(z轴位移量)不就行啦!来看下效果图,往上看,再往上看,再往上看,对了,就是图四的效果了...

      接下来给ul整体设置overflow:hidden;隐藏多出粉色边框的部分,就看到图一的效果了~

      

    下方轮播图切换点的控制:

      这个就很简单了,有m张图,就放m个点。点击第一个点(也是默认情况),将每个li绕x轴旋转(360/m)*0度;点击第二个点,将每个li绕x轴旋转(360/m)*1度;... 直到点击第m个点,将每个li绕x轴旋转(360/m)*(m-1)度。接下来,我们再给每个li多边体加上过渡transition:1s;transition-delay: (0.6 * (i-1))s; 这样就有每个li依次翻转的过渡效果啦,聪明的你又知道了,对,就是图二的效果了~

    perspecitve到底什么鬼?

      说了这么多,效果都实现了,我咋还不讲perspective呢?别急,这不是来了嘛... 如文章一开始所说,perspective会让你看到一种3d立体空间感,而非二位平面的体验了。本例中的perspective用在了class=‘swiper-wrapper’的蓝色边框元素上,赋值perspective:1000px; 它的取值越小,你在电影院的座位越靠前,视觉效果越近;反之,取值越大,你在电影院座位约靠后,视角越远。实际应用中,800-1000px效果较好,相当于电影院四五排的座位,got it?聪明的人一定get了... 下面上对比效果图:

     

    完整代码如下:

    HTML:

    1 <div class="swiper-wrapper">
    2         <ul id="swiper" class="swiper"></ul>
    3         <div id="dotlist" class="dots"></div>
    4     </div>

    CSS:

    复制代码
     1 .swiper-wrapper{
     2      600px;
     3     height: 350px;
     4     margin-top: 100px;
     5     padding: 10px;
     6     box-shadow: 0px 0px 10px 5px skyblue;
     7     transform-style: preserve-3d;
     8     perspective: 1000px;
     9     perspective-origin: 50% 50%;
    10 }
    11 .swiper-wrapper ul{
    12     position: relative;
    13      600px;
    14     height: 300px;
    15     box-shadow: 0px 0px 10px 2px pink;
    16     overflow: hidden;
    17     /*transform:translate/rotate(0px/deg); 若加这个属性,则3d效果消失。*/
    18 }
    19 .swiper-wrapper ul li{
    20     position: absolute;
    21     height: 300px;
    22     transform-style: preserve-3d;
    23     transform-origin:0px 50% 0px;
    24     transform: rotateX(0deg);
    25     transition: transform 1s;
    26 }
    27 .swiper-wrapper ul li div{
    28     position: absolute;
    29     left: 0;
    30     top: 0;
    31      100%;
    32     height: 100%;
    33     background-repeat: no-repeat;
    34 }
    35 .swiper-wrapper .dots{
    36     height: 46px;
    37     box-shadow: 0px 0px 10px 2px pink;
    38     text-align: center;
    39 }
    40 .dots span{
    41     display: inline-block;
    42      10px;
    43     height: 10px;
    44     margin: 10px;
    45     background-color: pink;
    46     border-radius: 10px;
    47     transition: all .5s;
    48 }
    49 .dots span.selected{
    50     background-color: red;
    51 }
    复制代码

    JS:

    复制代码
     1 <script>
     2         var img_num = 6;//li下的div个数,即z平面上多边盒的边数
     3         var cut_num = 6;//li个数,每个li代表切割的一块
     4 
     5         var ang = 360/img_num;//每张图片旋转的角度
     6         var ele_swiper = document.getElementById("swiper");
     7         var ele_dotlist = document.getElementById("dotlist");
     8         var ele_li;
     9         var ele_div;
    10         var ele_dot;
    11         var swiperWidth = ele_swiper.clientWidth;//整个swiper区域的宽度
    12         var width_li = swiperWidth/cut_num;//每个li的宽度
    13         var tranZ_dist = 260;//每张轮播图rotate之后要向z轴平移的距离
    14         var imgChosenId = 0;//初始显示第几张轮播图
    15         
    16         for (var i = 0; i < cut_num; i++) {//遍历li
    17             ele_li = document.createElement("li");
    18             
    19             for (var j = 0; j < img_num; j++) {//遍历div
    20                 //动态创建图片div
    21                 ele_div = document.createElement("div");
    22                 ele_li.appendChild(ele_div);
    23                 ele_div.style.backgroundImage = "url(images/"+(j+1)+".jpg)";
    24                 ele_div.style.backgroundSize = swiperWidth+"px 300px";//图片宽度等于swiper区域宽度
    25                 ele_div.style.backgroundPosition = (swiperWidth/cut_num)*i*(-1) + "px 0";//图片定位
    26                 ele_div.style.transform = "rotateX("+ang*j+"deg) translateZ("+tranZ_dist+"px)";
    27             }
    28 
    29             ele_swiper.appendChild(ele_li);
    30             ele_li.style.width = width_li+"px";
    31             ele_li.style.left = width_li*i+"px";
    32             (i > cut_num/2-1) && (ele_li.style.zIndex = (cut_num-i)*10);
    33             ele_li.style.transform = "translateZ("+tranZ_dist*(-1)+"px) rotateX("+ang*imgChosenId+"deg)"; //设置初始li翻转角度
    34         }
    35 
    36         //动态创建轮播点按钮
    37         for (var j = 0; j < img_num; j++) {
    38             ele_dot = document.createElement("span");
    39             ele_dot.setAttribute("idx",j);
    40             ele_dotlist.appendChild(ele_dot);
    41             if(j == imgChosenId){
    42                 ele_dot.className = "selected";
    43             }
    44         }
    45 
    46         //点击切换轮播图
    47         ele_dotlist.onclick = function doSwiper (e) {
    48             var targetNode = e.target;
    49             var idx;
    50             var swipeNode;
    51             if(targetNode.nodeName === "SPAN"){
    52                 for (var ii = 0; ii < this.childNodes.length; ii++) {
    53                     this.childNodes[ii].className = "";
    54                 };
    55                 targetNode.className = "selected";
    56                 idx = targetNode.getAttribute("idx");
    57 
    58 
    59                 for (var z = 0; z < cut_num; z++) {//遍历li
    60                     
    61                     /*for (var zi = 0; zi < img_num; zi++) {//遍历div
    62                         ele_swiper.childNodes[z].childNodes[zi]
    63 
    64 
    65                     }*/
    66 
    67                     swipeNode = ele_swiper.childNodes[z];
    68                     swipeNode.style.transform = "translateZ("+tranZ_dist*(-1)+"px) rotateX("+ang*idx+"deg)";
    69                     swipeNode.style.transitionDelay = 0.3*z+"s";
    70                 }
    71 
    72             }
    73         }
    74 
    75     </script>
    复制代码

    不算彩蛋的彩蛋

      本例中图片张数(div),轮播效果翻转片数(li),初始显示第几张--都是定义在js变量中的,我们也可以在页面上写几个input输入控制这些值。这么简单的事情我就不上代码了啊哈哈哈。就这样吧。

  • 相关阅读:
    友盟上报 IOS
    UTF8编码
    Hill加密算法
    Base64编码
    Logistic Regression 算法向量化实现及心得
    152. Maximum Product Subarray(中等, 神奇的 swap)
    216. Combination Sum III(medium, backtrack, 本类问题做的最快的一次)
    77. Combinations(medium, backtrack, 重要, 弄了1小时)
    47. Permutations II(medium, backtrack, 重要, 条件较难思考)
    3.5 find() 判断是否存在某元素
  • 原文地址:https://www.cnblogs.com/libin-1/p/6604481.html
Copyright © 2011-2022 走看看