javascript - 3d 盒子的网格(只有两个面)
问题描述
我有一个只有两个面(正面和底部)的 3d 盒子网格。每个盒子都有自己的视角。悬停时,盒子旋转;底面朝前。例如:
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 1000px;
margin: 50px auto;
}
.box-wrapper {
width: 25%;
height: 250px;
perspective: 1000px;
}
.box {
width: 100%;
height: 100%;
position: relative;
transition: transform .5s;
transform-style: preserve-3d;
}
.box .face {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
}
.box .face.front {
transform: translateZ(123.5px);
background-color: hsla(0, 100%, 50%, .5);
}
.box .face.bottom {
transform: rotateX(-90deg) translateZ(123.5px);
background-color: hsla(120, 100%, 50%, .5);
}
.box:hover {
transform: rotateX(90deg);
}
<div class="grid">
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
</div>
现在,这个设置的问题是盒子之间的重叠。我可以手动消除重叠,为此我需要进行以下更改/计算:
- 更改
width
_height
_margin
_.box-wrapper
- 更改和的
transform
(translateZ
).face.front
.face.bottom
而且由于一项更改会影响其他更改,因此这是有问题的。
例如,要消除上述设置(1000px 容器)中的重叠,需要进行以下更改:
.box-wrapper {
width: calc(25% - 29px); // why 29?
margin-right: 29px;
margin-bottom: 29px;
height: 221px;
}
.box .face.front {
transform: translateZ(110.5px); // half of box's width
}
.box .face.bottom {
transform: rotateX(-90deg) translateZ(110.5px);
}
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 1000px;
margin: 50px auto;
}
.box-wrapper {
width: calc(25% - 29px);
margin-right: 29px;
margin-bottom: 29px;
height: 221px;
perspective: 1000px;
}
.box {
width: 100%;
height: 100%;
position: relative;
transition: transform .5s;
transform-style: preserve-3d;
}
.box .face {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
}
.box .face.front {
transform: translateZ(110.5px);
background-color: hsla(0, 100%, 50%, .5);
}
.box .face.bottom {
transform: rotateX(-90deg) translateZ(110.5px);
background-color: hsla(120, 100%, 50%, .5);
}
.box:hover {
transform: rotateX(90deg);
}
<div class="grid">
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
</div>
我也打算让这个移动友好,所以随着窗口宽度的变化,我会改变容器的宽度(.grid
),并进行上述更改。所以我唯一的变量是容器宽度,它会随着窗口宽度的变化而变化,一个盒子应该占据容器宽度的 25%。如何自动进行此计算?由于计算包括透视和变换,我还不能想出任何东西。
即使我手动(试错)计算大屏幕断点的值(宽度、边距、变换),在某些时候我也需要使用 JS 自动计算,例如低于 768 像素。
解决方案
很明显,这个问题来自于translateZ
结合的角度。您正在通过积极的翻译使您的元素更接近您,而视角正在创造重叠。
为了避免这种情况,我们可以避免translateZ
使用其他配置来创建类似的效果。这是一个想法:
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 1000px;
margin: 50px auto;
}
.box-wrapper {
width: 25%;
height: 250px;
perspective: 1000px;
}
.box {
width: 100%;
height: 100%;
position: relative;
transition: transform .5s, transform-origin 0.5s;
transform-style: preserve-3d;
}
.box .face {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
box-sizing:border-box;
}
.box .face.front {
background-color: hsla(0, 100%, 50%, .5);
}
.box .face.bottom {
transform: rotateX(-90deg) translateY(50%) translateZ(125px);
background-color: hsla(120, 100%, 50%, .5);
}
.box:hover {
transform: rotateX(90deg) translateY(-100%);
transform-origin:top;
}
<div class="grid">
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
</div>
正如你所看到的,translateZ
前面的元素没有更多了,所以最初没有更多的重叠,然后我调整transform-origin
和平移以补偿translateZ
应用于底部元素。
所有使用的值都是使用百分比的相对值,因此您在计算时不会有任何问题。我还添加box-sizing:border-box
了在高度/宽度计算中包含边框,以便您可以250px / 2 = 125px
在translateZ
.
更新
我添加了一个过渡transform-origin
,以便以某种方式从中心旋转,而不是完全从顶部旋转。
更新 2
正如评论中所建议的,我们也可以更改transform-orgin
为center center -125px
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 1000px;
margin: 50px auto;
}
.box-wrapper {
width: 25%;
height: 250px;
perspective: 1000px;
}
.box {
width: 100%;
height: 100%;
position: relative;
transition: transform .5s;
transform-style: preserve-3d;
transform-origin:center center -125px;
}
.box .face {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
box-sizing:border-box;
}
.box .face.front {
background-color: hsla(0, 100%, 50%, .5);
}
.box .face.bottom {
transform: rotateX(-90deg) translateY(50%) translateZ(125px);
background-color: hsla(120, 100%, 50%, .5);
}
.box:hover {
transform: rotateX(90deg);
}
<div class="grid">
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
<div class="box-wrapper">
<div class="box">
<div class="face front">front face</div>
<div class="face bottom">bottom-face</div>
</div>
</div>
</div>
推荐阅读
- sql-server - 如何在 SQL Server 2017 中循环将多个表导出到平面文件 (csv)?
- jquery - Jquery如何只找到第一次出现
- c# - 在正则表达式替换中投射 1 美元
- ios - 性能方面,这是对类、结构、枚举等进行分组的更好方法
- apache - 与 Atlas HiveMetastoreBridge 代码相关的几个问题
- python - 获取一个基类的所有子类作为基类的类属性
- github - Travis CI 修改同一分支
- scala - 比较两个数据框中列的值
- c# - 如何将数据从 List 导出到具有不同 CSV 格式的 CSV 文件
- java - Java - 如果条件检查整数数组列表是否包含大于特定值的元素