CSS 3D:立方体 - 第2部分
#html #css #3d #cube

这是CSS立方体教程的第2部分。如果没有,您可能想检查part 1

现在,进入我们今天的主题:Cube!

更多几乎相同的立方体:

它与上次的基本设置大多是相同的:六堵墙,分为一个立方体,在一个单点透视的场景中。

<div class="scene">
  <div class="cube">
    <div class="wall"></div>
    <div class="wall"></div>
    <div class="wall"></div>
    <div class="wall"></div>
    <div class="wall"></div>
    <div class="wall"></div>
  </div>
</div>


body {
  margin: 0;
  box-sizing: border-box;
  background-color: black;
  display: grid;
  place-items: center;
  min-height: 100vh;
  font-size: .5vh;
}

.scene {
  width: 100em; 
  aspect-ratio: 1;
  perspective: 250em;
  position: absolute;
}

.scene * {
  transform-style: preserve-3d;
  position: absolute;
  inset: 0;
}

它看起来确实有些不同,这次是颜色的 - 但是您将能够创建与以前学到的相似的东西。所有区别在于我们这次如何组织墙壁。

分组成对

他们不会像上次:

那样通过个人放置来识别他们
  • Back

  • top

  • 底部

相反,前后,左和右,顶部和底部将根据.scene的绝对XYZ坐标系统的哪个轴将其分组为对:

  • 水平(x轴) - 左右壁

  • 垂直(Y轴) - 顶壁和底壁

  • 应用(Z轴) - 前壁和后壁

您可以看出的订单与第1部分不同 - 但这应该在此设置中感觉更有机。因此,让我们将类添加到对.Walls对。您应该结束:

<div class="scene">
    <div class="cube">
      <div class="wall horizontal">left</div>
      <div class="wall horizontal"></div>
      <div class="wall vertical"></div>
      <div class="wall vertical"></div>
      <div class="wall applicate"></div>
      <div class="wall applicate"></div>
    </div>
  </div>

您可以手动执行此操作或复制上面的代码。另外 - 如果您的代码编辑器具有EMMET扩展程序(VS代码和Codepen DO) - 您需要的只是输入:

.scene> .cube> .wall.horizo​​ntal*2+.wall.vertical*2+.wall.Applicate*2

上面提供了到目前为止所有内容的样式表。剩下的就是造型墙壁。他们需要一些颜色 - 每双。由于我们正在处理三重奏:X,Y和Z-我们将其与另外三个:RGB调色板配对:

.horizontal {
  background-color: red;
}

.vertical {
  background-color: green;
}

.applicate {
  background-color: blue;
}

现在,让我们开始使用 - 从第一堂课开始。如果我们只定位一堵墙,我们可以做到这一点:

.left {
  background-color: red;
  transform: rotateY(90deg) translateZ(50em);
}

如果我们对一对做到这一点,他们都会在同一位置。我们需要正确的一个在移动之前朝相反的方向转动:

.right {
  background-color: red;
  transform: rotateY(-90deg) translateZ(50em);
}

除了转弯的方向:顺时针或逆时针;正面及负面。仅一个变量,对这对的第一个和第二个元素都不同。

让我们定义它,然后:

.wall:nth-child(odd) {
  --direction: 1;
}

.wall:nth-child(even) {
  --direction: -1;
}

此伪级目标基于其在父容器中的序列中的位置。我们的假设.left是第一个。墙,假设。Right是第二个.Wall - 我们的确实可以分别仅在括号中排名1和2。但是我们做的方法可以解决问题:1是一个奇数,而2是一个偶数数字。更重要的是,这涵盖了其余对:顶部为3,前部为5- ergo,奇数和底部和背部和后部是4和6,这使得它们甚至是数字。

现在,让我们将变量应用于公式:

.horizontal {
  background-color: red;
  transform: rotateY( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

现在,对垂直行业做同样的事情:

.vertical {
  background-color: green;
  transform: rotateX( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

,所以我们知道哪一个是哪一个,让我们对第二个颜色倒置:

.wall:nth-child(even) {
  --direction: -1;
  filter: invert();
}

现在您应该看到这样的东西:

A 3D CSS cube in progress, with the top, bottom, left and right walls set in place, and front and back still on the base plane

注意,我们尚未定位的贴合墙是黄色的。它将是后墙,但是我们的CSS还不知道,它只是知道这是六堵墙中的最后一堵,所以它堆放在顶部。

也可以将它们设置在适当的位置。这是我们在第一部分中所做的:

.front {
  transform: translateZ(50em); /* pulls the wall closer to the viewer*/
}

.back {
  transform: translateZ(-50em); /* pushes the wall away from the viewer*/
}

所以,现在,我们可以做一个适用于.plical类的墙的版本:

.applicate {
  background-color:blue;
  transform: translateZ( calc( 90deg*var(--direction) ) );
}

随之而来的是,墙壁已经到位 - 现在的蓝色是正面的蓝色。让我们让整个事情都旋转,这样我们就可以从各个方面看一下:

.cube {
  animation: spin 6s linear infinite; /* adds a spinning animation */
}

@keyframes spin { /* the details of the animation: */
  100% { /* at the end point of the animation */
    transform: rotateY(360deg); /* ...the cube will have make a full 360 degree turn */
  }
}

看起来不错,对吗?

确实如此。从技术上讲。这是我们在第一部分中建立的结构的正确复制品 - 代码重复较少。在大多数情况下,它将完美地完成工作。但是,没有考虑到一件事:容器具有正面和背面的事实。当我们将面孔翻译成正面50em时,它将前进。当它以-50em的形式在Z轴上移动时,它有效地向后移动 - 我们认为Cube Spins的黄色壁实际上是其后侧。现在没有什么区别 - 但是如果您碰巧需要隐藏背面。

.wall {
  backface-visibility: hidden;
}

播放动画并关闭属性,以查看黄墙会发生什么

后墙消失了 - 或更确切地说是隐藏的。正如您所期望的那样,立方体内部的所有.Wall脸部都显得透明 - 但是黄色也是如此。我们不喜欢那样,对吗?为了保持一致性,我们将希望所有向外的墙壁都能看到,包括背部。那么,我们如何处理那条后墙,使其在适当的位置使其面对面?

移动之前需要进行180度转弯:

.back {
  transform: rotateY(180deg) translateZ(50em);
}

问题在于我们没有一个单独的类别的.back。它与前壁配对 - 在向前移动之前,它需要精确地转动0度:

.front {
  transform: rotateY(0deg) translateZ(50em);
}

从理论上讲,至少 - 因为同样,我们没有单独的.front类。我们有一对.plicalicate墙 - 首先需要将0DEG旋转,而后者则需要一半的墙。我们可以使用它。我们需要找到一个可以给我们的公式:

  1. 0deg for Pair

  2. 的180DEG

我们已经知道,在以前的对中,奇数将其值为90度,甚至是这些计算的结果,即使是-90deg的值 - 导致差异为180DEG:

.horizontal {
  background-color: red;
  transform: rotateY( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

.vertical {
  background-color: green;
  transform: rotateX( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

因此,在应用转换之前,我们需要将这些值偏移到90度,例如:

  • 90 + 90 = 180

  • 90-90-90 = 0

让我们复制.horizo​​ntal的转换,并通过添加90度旋转并从中减去原始旋转来调整它:

.applicate {
  background-color: green;
  transform: rotateY( calc( 90deg - 90deg*var(--direction) ) ) translateZ(50em);
}

最后,所有墙都在那里,正面向前进。顶部和底部的脸也 - 即使我们看不到它们,因为侧壁从我们的角度掩盖了它们。

让我们透露墙壁,只是为了确保:

.wall {
  opacity: .5;
}

.cube及其子女的样式(省略默认的.scene CSS设置)如下:

.horizontal {
  background-color: red;
  transform: rotateY( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

.vertical {
  background-color: green;
  transform: rotateX( calc( 90deg*var(--direction) ) ) translateZ(50em);
}

.applicate {
  background-color:blue;
  transform: rotateY( calc( 90deg - 90deg*var(--direction) ) ) translateZ(50em);
}

.wall {
  opacity: .5;
}

.wall:nth-child(odd) {
  --direction: 1;
}

.wall:nth-child(even) {
  --direction: -1;
  filter: invert();
}

.cube {
  animation: spin 6s linear infinite; /* adds a spinning animation */
}

@keyframes spin { /* the details of the animation: */
  100% { /* at the end point of the animation */
    transform: rotateY(360deg); /* ...the cube will have make a full 360 degree turn */
  }
}

它比第一部分中最终得到的要短 - 但是仍然有改进的余地。首先,所有墙壁都对50em进行了相同的翻译 - 每个班级都重申了这一事实。如果我们将常规公式应用于一般.wall类,该阶层的变量和50em的默认翻译?
怎么办

.horizontal {
  background-color: red;
  --turn: rotateY( calc( 90deg*var(--direction) ) );
}

.vertical {
  background-color: green;
  --turn: rotateX( calc( 90deg*var(--direction) ) );
}

.applicate {
  background-color:blue;
  --turn: rotateY( calc( 90deg - 90deg*var(--direction) ) );
}

.wall {
  opacity: .5;
  transform: var(--turn) translateZ(50em);
}

更好,不是吗?如果我告诉你我们可以走得更远怎么办?请注意,horizo​​ntal和.vertical如何具有相同的值:

calc(90deg*var( - 方向))

在各自的旋转中转换?另外,.horizo​​ntal和.plicate使用沿着同一轴的旋转。我们可以指定每个子集共享的变量来使用它。

首先,让我们指定旋转值的变量 - 并用公式中的变量替换这些值 - 一个用于.horizo​​ntal和.vertical的变量,一个仅适用于.Horizo​​ntal和。仅适用 /*,并且只需评论替换的样式而不是删除而不是删除他们,参考 */:

.horizontal, .vertical {
  --turnVal: calc( 90deg*var(--direction) );
}

.horizontal {
  background-color: red;
  /* --turn: rotateY( calc( 90deg*var(--direction) ) );*/
  --turn: rotateY( var(--turnVal) );
}

.vertical {
  background-color: green;
  /* --turn: rotateX( calc( 90deg*var(--direction) ) ); */
  --turn: rotateX( var(--turnVal) );
}

.applicate {
  background-color:blue;
  --turnVal: calc( 90deg - 90deg*var(--direction) );
  /* --turn: rotateY( calc( 90deg*var(--direction) ) ); */
  --turn: rotateY( var(--turnVal) );
}

.wall {
  opacity: .5;
  transform: var(--turn) translateZ(50em);
}

现在,让我们指定旋转轴的变量 - 并用公式中的变量替换这些值 - 一个用于.horizo​​ntal和.horizo​​ntal和.plinicate,而仅适用于.vertical:

.horizontal, .vertical {
  --turnVal: calc( 90deg*var(--direction) );
}

.horizontal {
  background-color: red;
  /* --turn: rotateY( var(--turnVal) ); */
  --turn: var(--turnAxis);
}

.vertical {
  background-color: green;
  --turnAxis: rotateX( var(--turnVal) );
  /* --turn: rotateX( var(--turnVal) ); */
  --turn: var(--turnAxis);
}

.horizontal, .applicate {
  --turnAxis: rotateY( var(--turnVal) );
  --turn: var(--turnAxis);
}

.applicate {
  background-color:blue;
  --turnVal: calc( 90deg - 90deg*var(--direction) );
  /* --turn: rotateY( var(--turnVal) ); */
  --turn: var(--turnAxis);
}

.wall {
  opacity: .5;
  transform: var(--turn) translateZ(50em);
}

这涵盖了所有碱基:变量 - turn在其内部定义其旋转轴的内部变量,该轴又有一个可变量的值。

这是一个华丽的纠结。

这是风格代码的真正戈尔迪安结:功能齐全且坚不可摧。哦,这么笨重。让我们看一下并进行一些战略性削减。您会注意到,当我们替换每个类别的变量时,我们基本上为所有类别都有相同的东西:

-tour:WAS(-tournaxis);

因此,我们可以将其从每个单独的班级中切下,然后将其粘贴到.wall类中:

.horizontal {
  background-color: red;
  /* --turn: var(--turnAxis); */
}

.vertical {
  background-color: green;
  --turnAxis: rotateX( var(--turnVal) );
  /* --turn: var(--turnAxis); */
}

.horizontal, .vertical {
  --turnVal: calc( 90deg*var(--direction) );
}

.horizontal, .applicate {
  --turnAxis: rotateY( var(--turnVal) );
}

.applicate {
  background-color:blue;
  --turnVal: calc( 90deg - 90deg*var(--direction) );
  /* --turn: var(--turnAxis); */
}

.wall {
  --turn: var(--turnAxis);
  opacity: .5;
  transform: var(--turn) translateZ(50em);
}

更好,不是吗?但是,实际上,不是 少得多的代码 - 所有这些都没有改变。从视觉上看,立方体本身看起来与其未经比较的前身相同:

优化仅影响引擎盖下发生的事情:计算机需要获取的数据量以及从中获取它们所需的位置数量。

您会讨厌我 - 但是有更多您可以优化!

好吧,也许不是今天。您现在确实已经受够了。

下次见?