网格的3d框(只有两个面)

aki*_*uri 6 javascript css css3 css-transforms css-animations

我有一个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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

现在,此设置的问题是框之间的重叠.我可以手动摆脱重叠,为此,我需要做以下更改/计算:

  • 改变width,heightmargin所述s(右和底部).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);
}
Run Code Online (Sandbox Code Playgroud)

.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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我还计划使这个移动设备友好,所以当窗口宽度改变时,我将改变容器(.grid)的宽度,并进行上述更改.因此,我所拥有的唯一变量是容器宽度,它将相对于窗口宽度而变化,并且盒子应占据容器宽度的25%.如何自动进行此计算?由于计算包括透视和变换,我还无法想出任何东西.

即使我手动计算(宽度,边距,变换)大屏幕断点的值(试错),在某些时候我需要自动使用JS,例如低于768px.

Tem*_*fif 3

很明显,这个问题是从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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,前面的元素不再存在translateZ,因此最初不再有重叠,然后我调整transform-origin平移以补偿translateZ应用于底部元素的平移。

使用的所有值都是使用百分比的相对值,因此计算时不会有任何问题。我还添加了box-sizing:border-box在高度/宽度计算中包含边框,以便您可以准确地使用 中高度 ( 250px / 2 = 125px)的一半translateZ

更新

我添加了一个过渡,以便transform-origin以某种方式从中心而不是完全从顶部进行旋转。

更新2

正如评论中所建议的,我们也可以更改transform-orgincenter 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);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)