3D 旋转导航栏

7

我正在尝试使用纯CSS、变换、过渡和透视创建一个3D导航栏。

以下是我的代码:

.navbar-fixed-bottom {
   background: transparent;
 }
 
 .navbar-perspective {
   width: 100%;
   height: 100%;
   position: relative;
   -webkit-perspective: 1100px;
   -moz-perspective: 1100px;
   perspective: 1100px;
   -webkit-perspective-origin: 50% 0;
   -moz-perspective-origin: 50% 0;
   perspective-origin: 50% 0;
 }
 
 .navbar-perspective > div {
   margin: 0 auto;
   position: relative;
   text-align: justify;
   -webkit-backface-visibility: hidden;
   -moz-backface-visibility: hidden;
   backface-visibility: hidden;
   -webkit-transition: all 0.5s;
   -moz-transition: all 0.5s;
   transition: all 0.5s;
   height: 50px;
   font-size:20px;
 }
 
 .navbar-primary {
   background-color: #cccccc;
   z-index: 2;
   -webkit-transform-origin: 0% 100%;
   -moz-transform-origin: 0% 100%;
   transform-origin: 0% 100%;
 }
 
 .navbar .navbar-secondary,
 .navbar .navbar-tertiary {
   background-color: #bfbfbf;
   width: 100%;
   -webkit-transform-origin: 0% 0%;
   -moz-transform-origin: 0% 0%;
   transform-origin: 0% 0%;
   z-index: 1;
   -webkit-transform: rotateX(-90deg);
   -moz-transform: rotateX(-90deg);
   transform: rotateX(-90deg);
   -webkit-transition: top 0.5s;
   -moz-transition: top 0.5s;
   transition: top 0.5s;
   position: absolute;
   top: 0;
 }
 
 .navbar .navbar-tertiary {
   background-color: #b3b3b3;
 }
 
 .navbar-rotate-primary {
   height: 50px;
 }
 
 .navbar-rotate-primary .navbar-primary {
   -webkit-transform: translateY(0%) rotateX(0deg);
   -moz-transform: translateY(0%) rotateX(0deg);
   transform: translateY(0%) rotateX(0deg);
 }
 
 .navbar-rotate-primary .navbar-secondary,
 .navbar-rotate-primary .navbar-tertiary {
   top: 100%;
   -webkit-transition: -webkit-transform 0.5s;
   -moz-transition: -moz-transform 0.5s;
   transition: transform 0.5s;
   -webkit-transform: rotateX(-90deg);
   -moz-transform: rotateX(-90deg);
   transform: rotateX(-90deg);
 }
 
 .navbar-rotate-secondary,
 .navbar-rotate-tertiary {
   height: 50px;
 }
 
 .navbar-rotate-secondary .navbar-primary,
 .navbar-rotate-tertiary .navbar-primary {
   -webkit-transform: translateY(-100%) rotateX(90deg);
   -moz-transform: translateY(-100%) rotateX(90deg);
   transform: translateY(-100%) rotateX(90deg);
 }
 
 .navbar-rotate-secondary .navbar-secondary,
 .navbar-rotate-tertiary .navbar-secondary {
   top: 100%;
   -webkit-transition: -webkit-transform 0.5s;
   -moz-transition: -moz-transform 0.5s;
   transition: transform 0.5s;
   -webkit-transform: rotateX(0deg) translateY(-100%);
   -moz-transform: rotateX(0deg) translateY(-100%);
   transform: rotateX(0deg) translateY(-100%);
 }
 
 .navbar-rotate-secondary-fallback .navbar-primary,
 .navbar-rotate-tertiary-fallback .navbar-primary {
   display: none;
 }
 
 .navbar-rotate-tertiary .navbar-secondary {
   -webkit-transform: translateY(-100%) rotateX(90deg);
   -moz-transform: translateY(-100%) rotateX(90deg);
   transform: translateY(-100%) rotateX(90deg);
 }
 
 .navbar-rotate-tertiary .navbar-tertiary {
   top: 100%;
   -webkit-transition: -webkit-transform 0.5s;
   -moz-transition: -moz-transform 0.5s;
   transition: transform 0.5s;
   -webkit-transform: rotateX(0deg) translateY(-100%);
   -moz-transform: rotateX(0deg) translateY(-100%);
   transform: rotateX(0deg) translateY(-100%);
 }
<html>

<head>

 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

</head>

<body>

 <nav id="navigation-bottom" class="navbar navbar-fixed-bottom">
  <div class="navbar-perspective">
   <div class="navbar-primary">
    <a href="javascript:void(0);" onclick="$('#navigation-bottom').attr('class','navbar navbar-fixed-bottom navbar-rotate-secondary')">Rotate To Face 2</a>
   </div>
   <div class="navbar-secondary">
    <a href="javascript:void(0);" onclick="$('#navigation-bottom').attr('class','navbar navbar-fixed-bottom navbar-rotate-tertiary')">Rotate To Face 3</a>
   </div>
   <div class="navbar-tertiary">
    <a href="javascript:void(0);" onclick="$('#navigation-bottom').attr('class','navbar navbar-fixed-bottom navbar-rotate-primary')">Rotate Back To Face 1</a>
   </div>
  </div>
 </nav>

</body>

</html>

我已经使用3D效果成功地旋转了前两个面,但第三个面看起来不对。当你从第二个面旋转到第三个面时,你会注意到顶部没有正确旋转并且看起来是平的。
非常感谢任何帮助。

这是一个JSFiddle:http://jsfiddle.net/wcb6kerq/ - Armin
2个回答

7

玩转翻转盒子

这与您最初的想法大不相同,但让我发布我的CSS并展示给您看,然后我会编辑一个更长的说明来解释它是如何以及为什么起作用的:

 

HTML

<section class="container">
    <nav id="nav-box" class="show-front">
        <div class="front">
            <a href="#">Show Bottom</a>
        </div>
        <div class="bottom">
            <a href="#">Show Back</a></div>
        <div class="back">
            <a href="#">Show Top</a></div>
        <div class="top">
            <a href="#">Show Front</a></div>
    </nav>
</section>

 

CSS

.container {
  position: relative;
  perspective: 1000px;
  transform: scale(0.95);
}

#nav-box {
  width: 100%;
  height: 50px;
  position: absolute;
  transform-origin: center center;
  transform-style: preserve-3d;
  transition: transform 0.5s;
}

#nav-box div {
  width: 100%;
  height: 50px;
  display: block;
  position: absolute;
  transition: background-color 0.5s;
}

#nav-box .front  { transform: rotateX(   0deg ) translateZ( 25px ); background-color: #ccc; }
#nav-box .back   { transform: rotateX( 180deg ) translateZ( 25px ); background-color: #ccc; }
#nav-box .top    { transform: rotateX(  90deg ) translateZ( 25px ); background-color: #ccc; }
#nav-box .bottom { transform: rotateX( -90deg ) translateZ( 25px ); background-color: #ccc; }

#nav-box.show-front  { transform: rotateY(    0deg ); }
#nav-box.show-front .bottom { background-color: #a0a0a0; }
#nav-box.show-front .top { background-color: #e0e0e0; }
#nav-box.show-back   { transform: rotateX( -180deg ); }
#nav-box.show-back .bottom { background-color: #e0e0e0; }
#nav-box.show-back .top { background-color: #a0a0a0; }
#nav-box.show-top    { transform: rotateX(  -90deg ); }
#nav-box.show-top .front { background-color: #a0a0a0; }
#nav-box.show-top .back { background-color: #e0e0e0; }
#nav-box.show-bottom { transform: rotateX(   90deg ); }
#nav-box.show-bottom .front { background-color: #e0e0e0; }
#nav-box.show-bottom .back { background-color: #a0a0a0; }

 

HTML/CSS的解释

设置我们的盒子

您开始想错了,我不得不说。 您的方法是“如何将这四个边缘视为一个框”而不是“如何在CSS中制作一个框?”

所以让我们学习如何制作一个盒子。

首先,我们建立一个box容器。由于这是一个导航框,让我们称其为nav-box。 我们应用的所有变换(除了阴影,稍后我们会处理)都将在nav-box上完成。

我们nav-box上的规则将确定它作为对象的行为。 让我们特别讨论两个规则:transform-origintransform-style

transform-origin默认为中心点(center center),但是我想在这里说一下。这基本上会告诉我们的盒子:“嘿,我们需要你围绕你的绝对中心旋转”。如果我们将其设置为transform-origin: center bottom',看起来就像盒子正在绕着底边旋转。center top`则会绕着顶部旋转。不过,我认为这不是你想要的。

transform-style需要设置为preserve-3d。这样做是指示浏览器不会干扰具有transform的元素。其他选项包括flat,它告诉浏览器忽略旋转下面的元素。我们在这里将preserve-3d设置为我们的nav-box,是为了确保我们应用于盒子侧面的transforms在我们transform父级时得以保留。真是好东西,不是吗?

设置我们的侧面

我们将侧面设置为nav-box的子元素,并使用rotateX将它们按照应有的顺序定位:
  • 正面的旋转角度为0
  • 背面的旋转角度为180deg
  • 底部的旋转角度为-90deg
  • 顶部的旋转角度为90deg

我们现在也可以使用.left { transform: rotateY(-90deg); } .right { rotateY(90deg); }来设置左右两侧。请注意,这两个示例中我们使用了Y轴。

其次,我们将translateZ值设置为25px。那么这是什么意思呢?这告诉我们的盒子需要相对于它们各自的旋转从父元素中心移动25px。为什么选择25px?因为它恰好是每个盒子高度的一半。这意味着它将与两侧的边缘很好地对齐。

然后是有趣的部分:

我们会根据盒子的位置和面向屏幕的部分来着色。背景颜色是相对于展示 show-frontshow-back等的方向而言的。底部会变暗,顶部则变亮。这个只是我觉得好看-实现这个任务并不一定需要,但可以让它看起来更真实。希望这能帮到你!

 


更新IE

Fiddle示例

所以,一旦我们修复了它的IE问题,这个东西就不太好看了,但它在这里。所有的preserve-3d做的就是在旋转容器时为您应用变换,而不是将它们平铺。如果我们不能使用preserve-3d,我们必须基于总旋转量进行计算。

这个解决方案就是这样做的。我不会像深入研究这个问题一样深入研究这个问题,只是强调需要更多JavaScript,并突出显示.rewind类:

#nav-box.rewind div {
    backface-visibility: hidden;
}

因为我们必须手动倒带这个解决方案,所以我们必须防止在错误的时间应用 z-index 重新排序。这就是 backface-visibility 的作用。 IE 中显示深度的示例 另一个示例,不需要使用 rewind 希望这能为您解决 IE 的问题。

谢谢您的回复,但是这在IE上不起作用,因为您正在使用preserve3d属性。诀窍是不要使用该属性。 - Armin
@Armin - 检查一下修改。我给你提供了一个IE兼容的修复方案。 - Josh Burgess
不太确定你所说的“透视”是什么意思,它绝对不是平的。尝试减少“透视”数值并设置“透视原点”,这将非常明显。 - Josh Burgess
如果您在它正在向后旋转时决定点击链接,该示例将会出现问题。 - porglezomp
@porglezomp - 没有考虑到为此进行修复。你指的是哪个例子? - Josh Burgess

-1
首先,非常感谢所有评论和回答这个问题的人,特别是Josh!
Josh,您的示例在支持preserve-3d的浏览器上完美运行。您发布的不带preserve-3d的更新在IE上显示为平面,因此仍未适用于所有浏览器。
经过三天的头痛,我终于意识到了问题所在。侧面的起点没有被正确设置。侧面需要围绕Z轴中间的一点旋转。
一旦我将起点更新为:
transform-origin: 25px 25px -25px;

一旦这个正确,你只需要更新对象的旋转即可。无需使用任何X、Y、Z坐标的变换。

这里有一个演示和一个解决方案,用于旋转并适用于包括IE10在内的所有浏览器的3D导航栏。

http://jsfiddle.net/tx0emcxe/


Josh,你在IE上的例子没有透视感。就像从正面看一个3D物体一样。当侧面旋转时,侧面不会向中间移动,因此显得平坦。 - Armin
1
@misterManSam - 你说得完全正确,我也很清楚。然而,我对提问者的态度和坚持认为我的答案不完整感到有点生气,即使在他自己接受的答案中也是如此。我并不担心赏金的颁发,而是这个问题。为了不对这里的社区不支持,我已经删除了我的评论。收到。 - Josh Burgess

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接