这是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.horizontal*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();
}
现在您应该看到这样的东西:
注意,我们尚未定位的贴合墙是黄色的。它将是后墙,但是我们的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旋转,而后者则需要一半的墙。我们可以使用它。我们需要找到一个可以给我们的公式:
-
0deg for Pair
-
我们已经知道,在以前的对中,奇数将其值为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 p> dev>
-
90-90-90 = 0 p> li>
让我们复制.horizontal的转换,并通过添加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);
}
更好,不是吗?如果我告诉你我们可以走得更远怎么办?请注意,horizontal和.vertical如何具有相同的值:
calc(90deg*var( - 方向))
在各自的旋转中转换?另外,.horizontal和.plicate使用沿着同一轴的旋转。我们可以指定每个子集共享的变量来使用它。
首先,让我们指定旋转值的变量 - 并用公式中的变量替换这些值 - 一个用于.horizontal和.vertical的变量,一个仅适用于.Horizontal和。仅适用 /*,并且只需评论替换的样式而不是删除而不是删除他们,参考 */:
.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);
}
现在,让我们指定旋转轴的变量 - 并用公式中的变量替换这些值 - 一个用于.horizontal和.horizontal和.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);
}
更好,不是吗?但是,实际上,不是 少得多的代码 - 所有这些都没有改变。从视觉上看,立方体本身看起来与其未经比较的前身相同:
优化仅影响引擎盖下发生的事情:计算机需要获取的数据量以及从中获取它们所需的位置数量。
您会讨厌我 - 但是有更多您可以优化!
好吧,也许不是今天。您现在确实已经受够了。
下次见?