• Intro to CSS 3D transforms


    原文地址:Intro to CSS 3D transforms,本文只是翻译了其中的一部分,省去了作者写文章的原因浏览器兼容部分(已经过时)

    Perspective

    元素需要设置需要设置perspective来激活3D效果,可以通过两种方式实现

    • 在transform属性中使用perspective方法

        transform: perspective( 600px );
      
    • 直接使用perspective属性

        perspective: 600px;
      

    NOTE:出于代码简介的目的,demo中的CSS样式没有使用浏览器前缀,在实际使用中需要使用-webkit-perspective, -moz-perspective, 等

    <style>
    	.container {
    		 200px;
    		height: 200px;
    		border: 1px solid #CCC;
    		margin: 0 auto 40px;
    	}
    	.box {
    		 100%;
    		height: 100%;
    	}
    	#red1 .box {
    	  background-color: red;
    	  transform: perspective( 600px ) rotateY( 45deg );
    	}
    </style>
    <section id="red1" class="container">
    	<div class="box red"></div>
    </section>
    

     

    <style>
    	#blue1{
    		perspective: 600px;
    	}
    	#blue1 .box {
    	  background-color: blue;
    	  transform: rotateY( 45deg );
    	}
    </style>
    
    <section id="blue1" class="container">
    	<div class="box blue1"></div>
    </section>
    

     

    这两种方式都会触发3D效果,但是有一点不同:第一种方式直接在一个元素上触发3D变形,但是当多个元素的时候变形效果和预期会有所不同,如果使用同样的方法作用于不同位置的元素的时候,每个元素会有自己的轴心,为了解决这个问题,需要在父元素使用perspective属性,这样每个子元素都共享相同的3D空间

    <style>
    	#red2 figure {
    	  background: red;
    	  transform: perspective( 400px ) rotateY(45deg);
    	}
    	.container figure {
    		display: block;
    		 55px;
    		height: 55px;
    		float: left;
    		margin: 5px;
    	}
    
    	#red2 figure {
    		background: #F00;
    		-webkit-transform: perspective( 400px ) rotateY( 45deg );
    		-moz-transform: perspective( 400px ) rotateY( 45deg );
    		-o-transform: perspective( 400px ) rotateY( 45deg );
    		transform: perspective( 400px ) rotateY( 45deg );
    	}
    </style>
    <section id="red2" class="container">
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
    </section>
    

     

    <style>
    	#blue2 {
    	  perspective: 400px;
    	}
    
    	#blue2 figure {
    	  background: blue;
    	  transform: rotateY( 45deg );
    	}
    </style>
    <section id="blue2" class="container">
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
        <figure></figure>
    </section>
    

     

    perspective属性的值决定了3D效果的强烈程度,可以认为是观察者到页面的距离。值越大距离越远,视觉上的3D效果就会相应的减弱。perspective: 2000px; 会产生一个好像我们使用望远镜看远方物体的3D效果,perspective: 100px;会产生一个小昆虫看大象的效果。

    3D效果默认轴心是元素中央,可以通过perspective-origin来修改轴心

    perspective-origin: 25% 75%;
    

    点击这里看一下作者写的一个有意思的立方体旋转页面

    3D变形方法

    作为一个web者,可能很熟悉两个方向:X & Y,表示元素的水平方向和垂直方向,在perspective激活的3D空间中我们可以在X、Y、Z三个坐标轴上对元素进行变形处理。3D变形使用的变形方法和2D变形一样,如果熟悉2D变形方法很容易掌握3D变形

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

    translateX()方法使元素延X轴移动,translateZ()使元素延Z轴(在3D空间中方向从前到后)移动。正值使元素离观察者更近,负值使元素变远。

    translateZ( -200px )
    translateZ( 200px )
    rotateX( 45deg )
    rotateY( 45deg )
    rotateZ( 45deg )

    有几个变形方法的缩写,这些方法需要把三个参数写全

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

    Pro-tip: fn3d()变形方法可以触发硬件加速HTML5 buzzwords in action

    任意3D操作会触发硬件加速,甚至可能变形只用到了2D的,或者没有做任何事情(比如translate3d(0,0,0))。需要注意的是这只是当前的表现,未来可能变化(这也是为什么我们没有写文档或者鼓励这么做),但是这在很多场景下非常有用,可以显著的提高渲染性能

    立方体

    创建六个面

    <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>
    

    为6个面设置基本的位置和尺寸样式

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

    1、2是前后面,3、4是左右,5、6是上下

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

    我们可以移除#cube .front样式声明,只用前面是可见的,上、下、左、右面与视角平行,所以看不到。需要从中心位置移动它们才可以看得到,每个面都是200px宽,每个面都需要从立方体中心移动100px;

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

    需要注意的是translateZ方法在rotate方法之后,变形方法的顺序很重要,吸收一会儿屌丝们,每面都先按自己的方向旋转,然后向外移动一个向量。

    为了用户看清楚,我们的3D变形不应该在扭曲不是active的面,但是我们延Z轴移动的时候,这种情况就难以避免。为了保持3D变形的瞬间,Safari先组合元素,然后再应用变形,因此文本会保持变形之前的样式,在3D变形中经常会出现显著的像素变化

    font-size: 2.5em

    transform: scale(2.5);

    transform: perspective(1200) translateZ(700px);

    通过之前例子可以发现无论perspective的值多小,或者变形的轴心在哪里,面1永远回到初始位置,好像3D变形对它没影响

    为了解决变形和像素保留问题,我们可以向后推一下3D对象,这样前面就会Z轴后移

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

    为了显示每个面,我们需要一个旋转立方体的样式,变形和当前面的方向相反,我们在#box 上切换必要的类来应用变形

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

    需要注意变形方法的顺序变了,我们先向后推元素,然后再旋转,再添加transition属性就完成了

    #cube { transition: transform 1s; }
    

    效果demo

    旋转木马

    和创建立方体类似,我们创建一个9个面的旋转木马

    <section 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>
    </section>
    

    现在应用一下基本的布局样式,给每个#carousel子元素面板20px的间距,这样每个面板的空间为210px

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

    下一步需要旋转每个面,9个面板,如果等分的话每个面板需要旋转40deg相对下一个

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

    现在外移元素,我们需要计算外移的距离,画一个草图,我们发现只有两个已知数:每个面板的宽度是210px,每个面板相对下一个旋转了40deg。拿出任意一个三角形都是右边的样子

    我们可以通过正切函数算出r

    image

    这样我们就知道知道需要移动288px

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

    如果需要改变面板的宽度或者数量,我们只需要应用一下公式就可以了,在JavaScript中

    var tz = Math.round( ( panelSize / 2 ) / 
      Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) );
    // or simplified to
    var tz = Math.round( ( panelSize / 2 ) / 
      Math.tan( Math.PI / numberOfPanels ) );
    

    最后我们需要再旋转木马上应用些变形

    transform: translateZ( -288px ) rotateY( -160deg );
    

    JS Bin

  • 相关阅读:
    4.19Java.util.Arrays类
    4.19Java数组的拷贝
    Inverse matrix of 4x4 matrix
    自言自语
    病了两天
    当年3ds max盗版光碟上的广告
    头晕的厉害
    复习了一下STL容器的知识
    一个简单的能处理MIPMAP的类
    空间变换代码,相当简洁优美
  • 原文地址:https://www.cnblogs.com/dolphinX/p/4075402.html
Copyright © 2020-2023  润新知