• CSS3 3D笨蛋教程


    英文原文An Introduction to CSS 3-D Transforms

    爱因斯坦说所有概念都必须介绍给儿童们,若他们无法了解,这些理论就毫无价值。

    透视

    一个元素需要一个透视点才能激活3D空间,有两种方法可以得到透视点:

    1. 使用transform属性,赋上perspective函数作为值。-webkit-transform: perspective(600);
    2. 或使用perspective属性。-webkit-perspective: 600;

    左边是使用transform属性的,右边使用perspective属性

    这两种方法都能触发3D空间,但却有所不同。首先,使用函数方式可以方便快捷地对单一元素应用3D变形,但是当你要应用在多个元素上时,它们可能不会按照预期的效果排列。如果你使用同样的transform属性应用在多个不同位置的元素上,每个元素都有自己的消失点。为了避免这种滑稽的效果,使用perspective属性应用在它们的父容器元素上,这样每个元素都共享了同一个消失点。

    左边是使用transform属性的,右边使用perspective属性

    perspective属性的值决定了3D效果的强度。

    你拿一本书平放在面前,看着书感受一下透视感,perspective属性值就是眼睛和书之间的距离,距离越远,数值越大,透视感越小;距离越近,数值越小,透视感越强。

    默认情况下,3D空间的消失点位于空间的正中央,你可以通过perspective-origin属性改变消失点的位置。

    CSS

    -webkit-perspective-origin: 25% 75%;

    3D变形函数

    作为一个Web设计师,你可能非常熟悉二维世界,X和Y,水平和垂直方向。在perspective创建的三维空间中,我们可以在三个维度上任意变换一个元素。

    3D变形使用的是和2D变形类似的transform属性。如果你熟悉2D变形,你会发现它和基本的3D变形很像。

    CSS

    rotateX(angle);
    rotateY(angle);
    rotateZ(angle);
    translateZ(tz);
    scaleZ(sz);

    我们借鉴translateX()这个函数,它令一个元素沿着水平X轴方向平移,而translateZ()函数则是沿着垂直的Z轴方向平移,它可以让3D空间由前往后运作。假设自己作为观察者,观察着电脑屏幕上的某个元素,translateZ函数的正向值(越来越大的值)令元素更靠近观察者,负向值则远离观察者。

    rotate函数可以在特定轴向上旋转元素。它的效果不同于你的直觉,通过下图可以很直观的感受到。

    可能很多人直觉中认为rotateX的效果会是rotateZ那个样子。

    transform函数的一些简写:

    CSS

    translate3d(tx,ty,tz);
    scale3d(sx,sy,sz);
    rotate3d(rx,ry,rz,angle);

    专家提醒:这些foo3d()变形函数在safari浏览器中会触发硬件加速效果。

    翻转卡片

    需要一些基本的标签:

    HTML

    <section class="container">
      <div id="card">
        <figure class="front">1</figure>
        <figure class="back">2</figure>
      </div>
    </section>

    .container元素持有3D空间,#card作为一张卡片对象。卡片的每一面就是一个独立的元素:.front和.back。将3d空间内的各个元素独立化,可以更容易理解和应用样式。

    我们准备添加一些3D样式:首先,对3D容器应用必要的perspective属性,同时添加任意的高宽或位置属性:

    CSS

    .container { 
       200px;
      height: 260px;
      position: relative;
      -webkit-perspective: 800;
    }

    现在#card元素可以在该3D空间中进行变形了。我们给#card元素添加绝对位置属性让它脱离文档的流式布局,再加上100%;height:100%,保证该对象的transform-origin可以在.center的正中央生效。

    让我们加上CSS3的transition属性,这样用户可以看到整个变形过程。

    CSS

    #card {
       100%;
      height: 100%;
      position: absolute;
      -webkit-transform-style: preserve-3d;
      -webkit-transition: -webkit-transform 1s;
    }

    .container的perspective仅仅应用在直接后代元素上,在本例中是应用在#card上。为了让所有后代元素都继承父元素的透视效果并在同样的3D空间中生效,父元素需要通过transform-style:preserve-3d来传递它的透视属性。如果没有transform-style,卡片的两个面都会失去立体效果,并且背面的旋转效果也会失效。

    要将卡片的两面定位到3D空间中,我们需要重置这些面元素的2D位置属性position:absolute。当卡片的正面朝向观察者时,为了隐藏相反的另一面,也就是背面,我们可以使用backface-visibility:hidden。

    CSS

    #card figure {
      display: block;
      position: absolute;
       100%;
      height: 100%;
      -webkit-backface-visibility: hidden;
    }

    要翻转.back面,我们添加基本的3D变形rotateY(180deg)

    CSS

    #card .front {
      background: red;
    }
    #card .back {
      background: blue;
      -webkit-transform: rotateY(180deg);
    }

    将两个面都设置好之后,#card需要一个相应的样式来翻转卡片。

    CSS

    #card.flipped {
      -webkit-transform: rotateY(180deg);
    }

    现在我们具备了一个可用的3D对象。为了翻转这张卡片,我们可以切换flipped类。当.flipped添加到#card上时,#card会旋转180度,将.back面露出来。

    立方体

    3D卡片对象是3D变形的入门好教材,一旦熟练掌握,你可能希望创建一些真正3D对象,例如棱柱。下面我们从立方体开始。 立方体的HTML标签和卡片类似,但是这次,我们需要六个子元素来创建立方体的六个面:

    HTML

    <section class="container">
      <div id="cube">
        <figure class="front">1</figure>
        <figure class="back">2</figure>
        <figure class="right">3</figure>
        <figure class="left">4</figure>
        <figure class="top">5</figure>
        <figure class="bottom">6</figure>
      </div>
    </section>

    先给六个面设置基本的定位和尺寸样式,一个叠一个放置在容器里。

    CSS

    .container {
       200px;
      height: 200px;
      position: relative;
      -webkit-perspective: 1000;
    }
    #cube {
       100%;
      height: 100%;
      position: absolute;
      -webkit-transform-style: preserve-3d;
    }
    #cube figure {
       196px;
      height: 196px;
      display: block;
      position: absolute;
      border: 2px solid black;
    }

    对于卡片,我们只需要翻转它的背面。对于立方体,需要翻转六个面中的五个。我们称第一面和第二面为前面和后面,第三第四面为侧面,第五第六面为顶面和底面。

    CSS

    #cube .front { -webkit-transform: rotateY(0deg); }
    #cube .back { -webkit-transform: rotateX(180deg); }
    #cube .right { -webkit-transform: rotateY(90deg); }
    #cube .left { -webkit-transform: rotateY(-90deg); }
    #cube .top { -webkit-transform: rotateX(90deg); }
    #cube .bottom { -webkit-transform: rotateX(-90deg); }

    现在每个面都旋转好了,并且只能看到正面。有四个面是垂直于观察者的,所以他们完全不可见。然后要使translate函数将他们从中心位置推到正确的边上。立方体的每个边长是200像素,从中心到边缘,每个边需要平移100像素。

    CSS

    #cube .front { -webkit-transform: rotateY(0deg) translateZ(100px); }
    #cube .back { -webkit-transform: rotateX(180deg) translateZ(100px); }
    #cube .right { -webkit-transform: rotateY(90deg) translateZ(100px); }
    #cube .left { -webkit-transform: rotateY(-90deg) translateZ(100px); }
    #cube .top { -webkit-transform: rotateX(90deg) translateZ(100px); }
    #cube .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }

    注意这里的translateZ函数紧接在rotate之后。顺序对于变形函数来说是很重要的,请花一些时间消化这句话。每一个面要先旋转到正确的朝向,然后沿着各自的朝向向外平移。

    现在我们的立方体看起来能用了,但还没完成。

    回到Z轴源点

    对于使用者,我们的3D变形不应该失真。但是当我们将元素从Z轴源点移开之后,不论是靠近观察者还是远离观察者,它都会失真。

    为了让3D变形看上去严谨,Safari先将元素复合,然后对其应用变形效果。也就是说,文本的抗锯齿效果会一直保持在变形之前的状态。

    为了解决失真问题,并还原像素,我们可以将整个3D对象向后推,这样它的正面将回到Z轴源点。

    CSS

    #cube { -webkit-transform: translateZ(-100px); }

    转动立方体

    我们需要一个能暴露任意面的样式。事实上我们只需要对整个立方体对象动手脚,在这里,立方体对象就是#cube。我们切换类名来应用不同的样式,一种样式就是一种变形,暴露不同的面。

    CSS

    #cube.show-front { -webkit-transform: translateZ(-100px) rotateY(0deg); }
    #cube.show-back { -webkit-transform: translateZ(-100px) rotateX(-180deg); }
    #cube.show-right { -webkit-transform: translateZ(-100px) rotateY(-90deg); }
    #cube.show-left { -webkit-transform: translateZ(-100px) rotateY(90deg); }
    #cube.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); }
    #cube.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }

    注意这里变形函数的次序和每个面的函数次序相反,首先要把立方体推回Z轴源点,然后旋转立方体。 完成之后,我们添加一个transition属性来展现旋转时的动画效果。

    CSS

    #cube { -webkit-transition: -webkit-transform 1s; }

    矩形棱柱

    立方体很容易制作,它是规则的,我们只需要关心一个度量值。但对于一个不规则的矩形棱柱呢?让我们尝试做一个300像素长,200像素宽,100像素高的棱柱。

    HTML标签和#cube的一样,但我们要把cube换成box,容器的样式保留大部分:

    CSS

    .container {
       300px;
      height: 200px;
      position: relative;
      -webkit-perspective: 1000;
    }
    #box {
       100%;
      height: 100%;
      position: absolute;
      -webkit-transform-style: preserve-3d;
    }

    现在定位各个面。每个面需要设置他们自己的尺寸,较小的面(左、右、顶、底)要定位到容器的正中央,这样他们可以方便地旋转然后置换到外侧。较薄的左面和右面设置位置为left:100px;((300-100)÷2)。较宽大的顶面和底面设置位置为top:500px((200-100)÷2)。

    CSS

    #box figure {
      display: block;
      position: absolute;
      border: 2px solid black;
    }
    #box .front,
    #box .back {
       296px;
      height: 196px;
    }
    #box .right,
    #box .left {
       96px;
      height: 196px;
      left: 100px;
    }
    #box .top,
    #box .bottom {
       296px;
      height: 96px;
      top: 50px;
    }

    旋转值可以和立方体案例中一致,但对于矩形棱柱,平移值需要一些变化。

    CSS

    #box .front { -webkit-transform: rotateY(0deg) translateZ(50px); }
    #box .back { -webkit-transform: rotateX(180deg) translateZ(50px); }
    #box .right { -webkit-transform: rotateY(90deg) translateZ(150px); }
    #box .left { -webkit-transform: rotateY(-90deg) translateZ(150px); }
    #box .top { -webkit-transform: rotateX(90deg) translateZ(100px); }
    #box .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }

    就像立方体一样,#box需要六个样式来暴露各个面。

    CSS

    #box.show-front { -webkit-transform: translateZ(-50px) rotateY(0deg); }
    #box.show-back { -webkit-transform: translateZ(-50px) rotateX(-180deg); }
    #box.show-right { -webkit-transform: translateZ(-150px) rotateY(-90deg); }
    #box.show-left { -webkit-transform: translateZ(-150px) rotateY(90deg); }
    #box.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); }
    #box.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }

    旋转木马

    本例的HTML标签和矩形棱柱、立方体、卡片一样。让我们构建一个9个面的木马。

    HTML

    <div class="container">
      <div id="carousel">
        <figure>1</figure>
        <figure>2</figure>
        <figure>3</figure>
        <figure>4</figure>
        <figure>5</figure>
        <figure>6</figure>
        <figure>7</figure>
        <figure>8</figure>
        <figure>9</figure>
      </div>
    </div>

    现在,应用一些基本的布局样式。让我们用left属性和right属性给每个面之间添加20像素的间距。每个面的有效宽度为210像素(其中实际为186像素,两边各2像素边框,边框外各10像素空隙,一共210像素)。

    CSS

    .container {
       210px;
      height: 140px;
      position: relative;
      -webkit-perspective: 1000;
    }
    #carousel {
       100%;
      height: 100%;
      position: absolute;
      -webkit-transform-style: preserve-3d;
    }
    #carousel figure {
      display: block;
      position: absolute;
       186px;
      height: 116px;
      left: 10px;
      top: 10px;
      border: 2px solid black;
    }

    下一步,旋转每个面。该旋转木马由9个面构成,要让9个面围成一圈,每个面要旋转40度(360÷9)。

    CSS

    #carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg); }
    #carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg); }
    #carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg); }
    #carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg); }
    #carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg); }
    #carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg); }
    #carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg); }
    #carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg); }
    #carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg); }

    现在每个面都位于旋转木马对象的正中央,像之前制作立方体和矩形棱柱时一样,每个面要向外推到正确的位置上。这里我们需要机选translate函数的值,看图:

    这张图是俯瞰该旋转木马对象,210像素是每个面的宽,r就是translate的值,简单的三角函数运算。

    我们要将每个面向外推288像素。

    CSS

    #carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg) translateZ(288px); }
    #carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg) translateZ(288px); }
    #carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg) translateZ(288px); }
    #carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg) translateZ(288px); }
    #carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg) translateZ(288px); }
    #carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg) translateZ(288px); }
    #carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg) translateZ(288px); }
    #carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg) translateZ(288px); }
    #carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg) translateZ(288px); }

    如果我们决定改变每个面的宽度或面的数量,我们只需要写一个JS函数,改变两个变量来获取正确的translateZ值。

    JavaScript

    var tz = Math.round( ( panelSize / 2 ) / Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) );
    // 或简单点
    var tz = Math.round( ( panelSize / 2 ) / Math.tan( Math.PI / numberOfPanels ) );

    总结经验

    即便是狭义相对论,去找一集BBC看一遍,相信你也能知道是什么东西,虽然不一定能明白背后运作的物理学定理。本文讲述的是CSS3D各种变形函数基本用法,这些函数实际上是对matrix3d()函数的封装,而matrix3d()函数则牵扯到线性代数、立体几何、三角学等的各种知识。未来的前端开发会变成什么样??

  • 相关阅读:
    nodejs程序发布的jenkins自动化脚本和问题记录
    jenkins代码rsync推送脚本带日志记录和代码分机房处理示例
    django入门到精通⑥消息管理器的升级处理,对关键词进行过滤示例
    django入门到精通⑤mako模板的使用
    django入门到精通④jinja2模板的使用
    django入门到精通③template模板功能和常用标签过滤器的使用
    hdfs副本调整不生效
    macOS 系统中,开发工具列表
    查看系统中安装了哪些python版本
    -p py, --python py target interpreter for which to create a virtual (either absolute path or identifier string) 中 identifier string 的含义
  • 原文地址:https://www.cnblogs.com/zjxwow/p/3175578.html
Copyright © 2020-2023  润新知