使用CSS构建旋转3D轮播

  • 知识需要:HTML,高级CSS,基本JavaScript
  • 需要:Modernizr,jQuery,Safari浏览器(暂不使用Chrome)
  • 项目时间: 1小时
  • 下载源文件

本文首次出现在.net杂志的第213期 - 这是世界上最畅销的网页设计师和开发者杂志。

到目前为止,我们都使用了CSS3的圆角,渐变和阴影,但这些只能触及现在可能的表面。 CSS转换,转换和动画采用我们心爱的HTML元素并对它们进行扭曲,补间和变异。什么曾经困扰脚本和故障动画现在流畅,硬件加速和简单。虽然纯粹主义者不喜欢使用CSS进行行为声明,但所有事情都变得更加简单。

有两组CSS转换,得到广泛支持2D的(工作草案)和更先进和令人兴奋的3D版本(工作草案),具有硬件加速奖金,我们将在我们的轮播中使用。

目前,只有Safari浏览器才能正确呈现这些内容(自2009年4月起)。 Chrome支持即将推出,早期的工作已在Mozilla开始。在IE9中,手指交叉进行2D变换,但3D很长一段时间不会发生。重要的是,iOS设备(iPhone,iPad和iPod touch)支持硬件加速的3D转换。基于浏览器支持,为简洁起见,本教程中仅使用与WebKit兼容的CSS。但请注意,面板上的线性渐变在最新的webkit中无法正确显示,因为它使用的是旧语法。

基本的HTML5大纲

我们将创建一个六面板旋转旋转木马,为了保持简单,我们将使其固定宽度。让我们从基本的HTML5大纲开始。我们将把所有的CSS都放进去Carousel.css和JavaScript中的Carousel.js。我们也在使用Modernizr的检测3D转换功能(以及HTML5垫片)和jQuery。当支持3D变换时,Modernizr将添加一个类Csstransforms3d到我们可以在CSS中使用的HTML标记。

  1. <HTML>
  2. <>
  3. ...
  4. <链接rel =“stylesheet”type =“text / css”href =“css / carousel.css”/>
  5. <脚本SRC = “JS / Modernizr的-1.6.min.js”> 脚本>
  6. 头>
  7. <身体> ......
  8. <脚本SRC = “JS / jQuery的1.4.4.min.js”> 脚本>
  9. <脚本SRC = “JS / carousel.js”> 脚本>
  10. 身体>
  11. HTML>

对于我们的轮播,我们将使用一个列表,每个列表项都是一个面板。要导航轮播,有一些上一个和下一个链接将挂钩到某些JavaScript:

    • 小组标题

    • ...

  • ...(共6个面板)
  • 在我们深入研究3D领域之前,我们应该设置一些基本样式,因此轮播看起来大致与我们预期的一样。旋转木马有黑色背景和花式径向渐变(从深灰色到黑色);它以浅色边框为中心。只有在面板动画时才会显示背景。我们需要添加溢出:隐藏以后这个元素就像一个窗口,但在构建它时看到所有内容是有帮助的:

    1. #carousel {
    2. 宽度:580px;
    3. 身高:300px;
    4. 背景:#000;
    5. 背景:-webkit-gradient(线性,右下,右上,颜色停止(1,rgb(70,70,70)),颜色停止(0.57,rgb(0,0,0)));
    6. 保证金:0自动;
    7. border:1px solid #ccc;
    8. }

    容器是绝对定位的,宽度稍大(600px),因此我们可以将面板稍微分开,并使它们在动画期间更具视觉吸引力:

    1. #carousel .container {
    2. 宽度:600px;
    3. }
    4. #carousel .panels,
    5. #carousel .panels> li {
    6. 宽度:600px;
    7. 显示:块;
    8. 位置:绝对;
    9. }
    10. #carousel .container,
    11. #carousel .panels> li {
    12. 身高:300px;
    13. }

    最后来到我们的面板:580px的总宽度,与旋转木马相同的尺寸,但有一点填充,渐变和文字阴影来美化它。

    Our styled carousel and panel before we apply any 3D transforms

    在我们应用任何3D变换之前,我们的风格旋转木马和面板

    在开发过程中,使这个面板略微透明可以帮助解决错误并更清楚地说明3D结构:

    1. #carousel .panels> li> div {
    2. 背景:#fff;
    3. 背景:-webkit-gradient(线性,右下,右上,颜色停止(1,rgb(255,255,255)),颜色停止(0.57,rgb(230,230,230)));
    4. 身高:260px;
    5. 宽度:540px;
    6. 填充:20px;
    7. Text-shadow:0 1px 0 #fff;
    8. }

    3D需要透视

    要开始我们的3D冒险,我们需要为我们的旋转木马提供一些视角。这是一个带有大量解释的单线程:

    1. .csstransforms3d #carousel {
    2. -webkit-perspective:800;
    3. }

    这是科学部分。在三维中,我们有三个平面,x,y和z。 x和y分别从左到右和从上到下。 z平面从前向后延伸,垂直于x和y。透视值定义z = o平面距观察者的距离,这会影响3D效果的大小。

    数字较小时,z = 0平面非常接近,小的变化会产生很大的影响。想象一下,站在摩天大楼下面直视:你很小,物体很大。由于数字很大,z = 0平面很远,变化更加微妙 - 它是同一个摩天大楼,但这次你正在飞向上方俯视。围绕800至1,000标记的视角感觉自然。默认情况下,透视的原点(即其消失点)居中 - 这很适合我们,但必要时可以更改它:

    1. -webkit-perspective-origin:50%50%;

    透视图适用于所有子元素,带透视图的元素成为包含块。这可能听起来很复杂,但请记住:所有困难的透视计算都是由浏览器执行的,并且在使用代码后很快就会成为第二天性。

    还有一件事:具有透视的元素的直接子元素将被定位在3D空间中(例如,Div.container),但他们的孩子将被打成2D。我们可以通过设置来避免这种情况变换风格保留-3D

    1. .csstransforms3d #carousel .container,
    2. .csstransforms3d #carousel .panels {
    3. -webkit-transform-style:preserve-3d;
    4. }

    一圈面板

    当我们从一个面板移动到面板时,旋转木马将旋转。对于此效果,我们首先需要使用关于顶部到底部y轴的3D变换将每个面板定位在圆中。此示例中有六个面板,因此每个面板与下一个面板成60度:

    1. .csstransforms3d #carousel li:nth-child(1){ - webkit-transform:rotateY(0deg)}
    2. .csstransforms3d #carousel li:nth-child(2){ - webkit-transform:rotateY(-60deg)}
    3. .csstransforms3d #carousel li:nth-child(3){ - webkit-transform:rotateY(-120deg)}
    4. .csstransforms3d #carousel li:nth-child(4){ - webkit-transform:rotateY(-180deg)}
    5. .csstransforms3d #carousel li:nth-child(5){ - webkit-transform:rotateY(-240deg)}
    6. .csstransforms3d #carousel li:nth-child(6){ - webkit-transform:rotateY(-300deg)}

    但是只围绕y轴旋转会将所有面板放在每个面板的顶部:

    Oh dear, that's not quite right. The panels are rotated but they're sitting on top of each other

    亲爱的,这不太对劲。面板旋转但它们彼此叠加

    我们需要将它们展开,以便每个列表元素的边缘接触下一个,并形成一个圆。

    这很简单:在z平面上平移会使每个面板远离中心点。计算准确的平移距离,即圆的半径,需要一点三角法。在这种情况下,对于6个宽度为600px的面板,它大约是519px。

    Our six panels are calculated in a circle. We can calculate the radius of the circle using trigonometry

    我们的六个面板围成一圈计算。我们可以使用三角法计算圆的半径

    翻译519px会将面板面放在圆的外侧:-519px将向相反方向发送它们,它们将在内侧。这取决于您希望旋转木马的行为方式。在这个例子中,我们将在内部向外看,所以我们将使用-519px,我们的最终转换看起来像:

    1. .csstransforms3d #carousel li:nth-child(1){ - webkit-transform:rotateY(0deg)translateZ(-519px); }
    2. ...

    A circle of panels translated by -519px. We're inside the circle and the panels move around us

    一小组面板由-519px翻译。我们在圈内,面板在我们周围移动

    唉,还有另一个问题:所有的面板都在一个圆圈中,但最前面的部分已经放大了,看起来很大。

    我们已经在z平面上移动了面板。使用我们的容器,我们可以通过向后移动面板来改变我们查看圆圈的位置,即通过将Z等量转换为相反的方向:

    1. .csstransforms3d #carousel .container {
    2. -webkit-transform:translateZ(519px);
    3. }

    After translating our panels by -519px, we're looking at the circle from the wrong position. We need to translate the container

    在将我们的面板翻译为-519px之后,我们正在从错误的位置查看圆圈。我们需要翻译容器

    旋转圆圈

    我们的圈子是完整的,我们坐在它的中间,但我们如何从一个面板移动到另一个面板?

    我们可以移动容器,而不是改变每个元素的位置。该