3D实现思路分享

来自技术开发小组内部wiki
跳转至: 导航搜索

在CSS2中,我们的页面都是静态的,网页设计师也习惯把它作为页面效果的设计工具。但往往有些页面效果不只是静态的,比如说,如何实际移动一些元素?如何更改元素的外观——旋转或缩放? 多年来,Web设计师为了给修改页面的外观,都依赖于图片、Flash或JavaScript才能完成。不过,CSS3将要改变设计师这种思维,进入CSS3时代,借助CSS3就可以轻松倾斜、缩放、移动以及翻转元素。看以下两个例子之前先来了解CSS3的一些基本知识


'1: css3中-moz、-ms、-webkit分别代表的意思是什么呢? -moz代表firefox浏览器私有属性-ms代表ie浏览器私有属性-webkit代表safari、chrome -o'代表opera浏览器私有属性


2: px:绝对单位,页面按精确像素展示 em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个固定的值。


3: box-sizing属性可以为三个值之一:content-box(default),border-box,padding-box。 content-box,border和padding不计算入width之内 padding-box,padding计算入width内 border-box,border和padding计算入width之内,其实就是怪异模式了~


4: perspective 属性定义 3D 元素距视图的距离,以像素计。该属性允许您改变 3D 元素查看 3D 元素的视图。 当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。 注释:perspective 属性只影响 3D 转换元素。


5: transform-style属性是3D空间一个重要属性,指定嵌套元素如何在3D空间中呈现。他主要有两个属性值:flat和preserve-3d。 其中flat值为默认值,表示所有子元素在2D平面呈现。preserve-3d表示所有子元素在3D空间中呈现。 也就是说,如果对一个元素设置了transform-style的值为flat,则该元素的所有子元素都将被平展到该元素的2D平面中进行呈现。沿着X轴或Y轴方向旋转该元素将导致位于正或负Z轴位置的子元素显示在该元素的平面上,而不是它的前面或者后面。如果对一个元素设置了transform-style的值为preserve-3d,它表示不执行平展操作,他的所有子元素位于3D空间中。


CSS3的transform属性指一组转换函数。 CSS3变形中具有X /Y可用的函数:'rotate()、translateY()、'translateX()、translateY()、scaleX()、scaleY()skewX()和skewY()


以下是一些例子


实例一


<!DOCTYPE html> <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

 <meta charset="UTF-8">
 <title>HTML5 3D立方体旋转动画DEMO演示</title>
   <link rel="stylesheet" href="css/style.css" media="screen" type="text/css">

</head>

<body>

<cube>
<back></back>
<bottom></bottom>
<front></front>
<left></left>
<right></right>
<top></top>

</cube> </body>

</html>

<style type="text/css"> * {

   -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;

}

html {

   background: -webkit-radial-gradient(center, ellipse, #430d6d 0%, #000000 100%);
background: radial-gradient(ellipse at center, #430d6d 0%, #000000 100%);
height: 100%;

}

body {

   width: 20em;
height: 20em;
left: 50%;
margin-left: -10em;
margin-top: -10em;
-webkit-perspective: 1000px;
-ms-perspective: 1000px;
perspective: 1000px;
position: absolute;
top: 50%;

}

cube {

   -webkit-animation: 6s spin linear infinite;
animation: 6s spin linear infinite;
height: 100%;
position: absolute;
-webkit-transform-style: preserve-3d;
-ms-transform-style: preserve-3d;
transform-style: preserve-3d;
width: 100%;

}

cube * {

   background: -webkit-linear-gradient(270deg, rgba(0, 0, 0, 0) 0px, rgba(54, 226, 248, 0.5) 0%, rgba(54, 226, 248, 0.5) 3px, rgba(0, 0, 0, 0) 0px), -webkit-linear-gradient(0deg, rgba(0, 0, 0, 0) 0px, rgba(54, 226, 248, 0.5) 0%, rgba(54, 226, 248, 0.5) 3px, rgba(0, 0, 0, 0) 0px);
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0px, rgba(54, 226, 248, 0.5) 0%, rgba(54, 226, 248, 0.5) 3px, rgba(0, 0, 0, 0) 0px), linear-gradient(90deg, rgba(0, 0, 0, 0) 0px, rgba(54, 226, 248, 0.5) 0%, rgba(54, 226, 248, 0.5) 3px, rgba(0, 0, 0, 0) 0px);
-webkit-background-size: 2.5em 2.5em, 2.5em 2.5em;
background-size: 2.5em 2.5em, 2.5em 2.5em;
background-color: rgba(0, 0, 0, 0.5);
border: 2px solid rgba(54, 226, 248, 0.5);
-webkit-box-shadow: 0 0 5em rgba(0, 128, 0, 0.4);
box-shadow: 0 0 5em rgba(0, 128, 0, 0.4);
display: block;
height: 20em;
position: absolute;
width: 20em;

}

cube *:before {

   background: -webkit-radial-gradient(center, ellipse, rgba(0, 0, 0, 0) 30%, rgba(0, 128, 0, 0.2) 100%);
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 30%, rgba(0, 128, 0, 0.2) 100%);
content: ;
height: 100%;
position: absolute;
width: 100%;

}

back {

   -webkit-transform: rotateX(180deg) translateZ(10em);
-ms-transform: rotateX(180deg) translateZ(10em);
transform: rotateX(180deg) translateZ(10em);

}

bottom {

   -webkit-transform: rotateX(-90deg) translateZ(10em);
-ms-transform: rotateX(-90deg) translateZ(10em);
transform: rotateX(-90deg) translateZ(10em);

}

front {

   -webkit-transform: rotateY(0deg) translateZ(10em);
-ms-transform: rotateY(0deg) translateZ(10em);
transform: rotateY(0deg) translateZ(10em);

}

left {

   -webkit-transform: rotateY(-90deg) translateZ(10em);
-ms-transform: rotateY(-90deg) translateZ(10em);
transform: rotateY(-90deg) translateZ(10em);

}

right {

   -webkit-transform: rotateY(90deg) translateZ(10em);
-ms-transform: rotateY(90deg) translateZ(10em);
transform: rotateY(90deg) translateZ(10em);

}

top {

   -webkit-transform: rotateX(90deg) translateZ(10em);
-ms-transform: rotateX(90deg) translateZ(10em);
transform: rotateX(90deg) translateZ(10em);

}

@-webkit-keyframes spin {

   from
{
  -webkit-transform: translateZ(-10em) rotateX(0) rotateY(0deg);
  transform: translateZ(-10em) rotateX(0) rotateY(0deg);
}
   to
{
  -webkit-transform: translateZ(-10em) rotateX(360deg) rotateY(360deg);
  transform: translateZ(-10em) rotateX(360deg) rotateY(360deg);
}

}

@keyframes spin {

   from
{
  -webkit-transform: translateZ(-10em) rotateX(0) rotateY(0deg);
  transform: translateZ(-10em) rotateX(0) rotateY(0deg);
}
   to
{
  -webkit-transform: translateZ(-10em) rotateX(360deg) rotateY(360deg);
  transform: translateZ(-10em) rotateX(360deg) rotateY(360deg);
}

}

</style>



实例二



<!DOCTYPE html> <html>

<head>

 <meta charset="UTF-8">
 <title>HTML5 SVG 3D空间模型DEMO演示</title>
   <link rel="stylesheet" href="css/style.css" media="screen" type="text/css" />

</head>

<body>

 <main>
<article>
<section id="perspective">
<svg id="grid">
  <rect x="1" y="1" width="998" height="998"/>
  <line x1="200" y1="2" x2="200" y2="998"/>
  <line x1="400" y1="2" x2="400" y2="998"/>
  <line x1="600" y1="2" x2="600" y2="998"/>
  <line x1="800" y1="2" x2="800" y2="998"/>
  <line x1="2" y1="200" x2="998" y2="200"/>
  <line x1="2" y1="400" x2="998" y2="400"/>
  <line x1="2" y1="600" x2="998" y2="600"/>
  <line x1="2" y1="800" x2="998" y2="800"/>
</svg>
<section id="axis">
  <figure id="X">
       </figure>
  <figure id="Y">
       </figure>
  <figure id="Z">
       </figure>
</section>
<section id="graph"></section>
</section>
</article>
<nav>
<button onmousedown="select(this)">Pan</button>
<button onmousedown="select(this)">Rotate</button>
<button onmousedown="select(this)">Zoom</button>
<button onmousedown="resetViewport()">Reset viewport</button>
<section id="menu">Your menu</section>
</nav>
<label>‹</label>
<aside>

This CSS 3D project works fine only in WebKit based browsers

Middle mouse button - Pan view

Alt + Left mouse button - Rotate view

Scroll wheel - Zoom in / out

 </aside>

</main>

 <script type="text/javascript">
var $ = document.querySelectorAll.bind(document);
   /* -------------------------------- */
/* ---------- Navigation ---------- */
/* -------------------------------- */
var article = $('article')[0];
var perspective = $('#perspective')[0];
var buttons = $('button');
   var click = false;
var cursor = { x: 0, y: 0 };
var transform = {
position: { x: 0, y: 0 },
rotation: { x: 0, y: 0 },
zoom: 0
};
var target = {
position: { x: 0, y: 0 },
rotation: { x: -20, y: -45 },
zoom: 100
};
var targetOnDown = {
position: { x: 0, y: 0 },
rotation: { x: 0, y: 0 },
zoom: 0
};
   article.onmousedown = function(e) {
if (e.which < 3) {
  if (e.which == 2) article.className = 'pan';
  if (article.className == 'pan')
    article.style.cursor = '-webkit-grabbing';
  cursor.x = e.pageX;
  cursor.y = e.pageY;
  targetOnDown.position.x = target.position.x;
  targetOnDown.position.y = target.position.y;
  targetOnDown.rotation.x = target.rotation.x;
  targetOnDown.rotation.y = target.rotation.y;
  targetOnDown.zoom = target.zoom;
  click = true;
}
};
article.onmousemove = function(e) {
if (click) {
  switch (article.className) {
    case 'pan':    target.position.x = targetOnDown.position.x + e.pageX - cursor.x;
                   target.position.y = targetOnDown.position.y + e.pageY - cursor.y;
                   break;
         case 'rotate': target.rotation.x = targetOnDown.rotation.x - (e.pageY - cursor.y) * 0.3;
                   target.rotation.y = targetOnDown.rotation.y + (e.pageX - cursor.x) * 0.3;
                   break;
         case 'zoom':   target.zoom = targetOnDown.zoom - (e.pageY - cursor.y) * 0.4;
                   if (target.zoom < 50) target.zoom = 50;
                   break;
  }
}
};
article.onmouseup = function(e) {
click = false;
if (article.className == 'pan')
  article.style.cursor = ;
if (e.which == 2) returnValue();
};
   onkeydown = function(e) {
if (e.altKey) article.className = 'rotate';
};
onkeyup = function(e) {
if (e.keyCode == 18) returnValue();
};
   article.addEventListener('mousewheel', scroll, false);
article.addEventListener('DOMMouseScroll', scroll, false);
function scroll(e) {
e.preventDefault();
var delta = (e.wheelDelta) ? e.wheelDelta : - e.detail;
target.zoom += (delta > 0) ? 15 : -15;
if (target.zoom < 50) target.zoom = 50;
}
   function select(button) {
[].forEach.call(buttons, function(b) { if (b != button) b.removeAttribute('class'); });
(button.className) ? button.removeAttribute('class') : button.className = 'selected';
switch (button.innerHTML) {
  case 'Pan': (article.className == 'pan') ? article.removeAttribute('class') : article.className = 'pan'; break;
  case 'Rotate': (article.className == 'rotate') ? article.removeAttribute('class') : article.className = 'rotate'; break;
  case 'Zoom': (article.className == 'zoom') ? article.removeAttribute('class') : article.className = 'zoom'; break;
}
}
   function returnValue() {
for (var i = 0; i < buttons.length; i++)
  if (buttons[i].className == 'selected')
    var str = buttons[i].innerHTML.toLowerCase();
if (str) article.className = str;
else article.removeAttribute('class');
}
   function resetViewport() {
target.position.x = target.position.y = 0;
target.rotation.x = -20;
target.rotation.y = -45;
target.zoom = 100;
}
   (function animate() {
transform.position.x += (target.position.x - transform.position.x) * 0.2;
transform.position.y += (target.position.y - transform.position.y) * 0.2;
transform.rotation.x += (target.rotation.x - transform.rotation.x) * 0.1;
transform.rotation.y += (target.rotation.y - transform.rotation.y) * 0.1;
transform.zoom += (target.zoom - transform.zoom) * 0.1;
     transform.position.x = parseFloat(transform.position.x.toFixed(2));
transform.position.y = parseFloat(transform.position.y.toFixed(2));
transform.rotation.x = parseFloat(transform.rotation.x.toFixed(2));
transform.rotation.y = parseFloat(transform.rotation.y.toFixed(2));
transform.zoom = parseFloat(transform.zoom.toFixed(2));
     perspective.style.transform =
perspective.style.msTransform =
perspective.style.mozTransform =
perspective.style.webkitTransform = 'translate(' + transform.position.x + 'px, ' + transform.position.y + 'px) rotateX(' + transform.rotation.x + 'deg) rotateY(' + transform.rotation.y + 'deg) scale3d(' + transform.zoom / 100 + ', ' + transform.zoom / 100 + ', ' + transform.zoom / 100 + ')';
requestAnimationFrame(animate);
})();
 </script>

</body>

</html>



以下是一些参考资料


linear-gradient讲解

http://www.cnblogs.com/lhb25/archive/2013/01/30/css3-linear-gradient.html

transform 讲解

http://www.w3cplus.com/content/css3-transform/

http://www.alixixi.com/web/a/2013112291742.shtml

perspective讲解

http://blog.163.com/hongshaoguoguo@126/blog/static/18046981201392411302262/

animation讲解

http://www.tuicool.com/articles/BN3iiq