纯css 3D立体加载动画
基础知识以及参数示例
虽然css能够实现3d动画,但是在实际开发中运用较少,对于部分基础css知识,会存在部分盲区,所以需要提前知道一下知识点,用于方便理解。
- transform-style: preserve-3d,设置元素所在空间是3d还是平面
- perspective-origin: 观察者的位置
- perspective 景深,理论为观察者与z=0的平面距离;
- translateX
- translateY
- translate3d
- rotate3d
- rotateX
- rotateY
- rotateZ
- css - animation动画
示例-1
当前示例虽然实现了正方形六面的3d,但是由于容器有背景参照,能够清楚的看出,容器是提供给六个面3d空间,它本身处于2地平面空间
<template>
<div class="custom-wrapper">
<div class="container-1">
<div class="cube-1">
<div class="cube-item front">
1
</div>
<div class="cube-item back">
2
</div>
<div class="cube-item right">
3
</div>
<div class="cube-item left">
4
</div>
<div class="cube-item top">
5
</div>
<div class="cube-item bottom">
6
</div>
</div>
</div>
</div>
</template>
<style lang='scss' scoped>
.custom-wrapper {
--w: 100px;
.container-1 {
position: relative;
.cube-1 {
position: relative;
width: 100%;
height: 500px;
background-color: rgba(black, 0.5);
backface-visibility: visible;
perspective-origin: 100% 0%;
transform-style: preserve-3d;
perspective: 500px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
color: white;
text-align: center;
line-height: 100px;
.cube-item {
position: absolute;
width: var(--w);
height: var(--w);
border-radius: 10px;
border: 2px solid rgba(white, 0.9);
background-color: rgba(white, 0.3);
}
.front {
background: rgba(0, 0, 0, 0.3);
transform: translateZ(56px);
}
.back {
background: rgba(0, 255, 0, 1);
color: black;
transform: rotateY(180deg) translateZ(56px);
}
.right {
background: rgba(196, 0, 0, 0.7);
transform: rotateY(90deg) translateZ(56px);
}
.left {
background: rgba(0, 0, 196, 0.7);
transform: rotateY(-90deg) translateZ(56px);
}
.top {
background: rgba(196, 196, 0, 0.7);
transform: rotateX(90deg) translateZ(56px);
}
.bottom {
background: rgba(196, 0, 196, 0.7);
transform: rotateX(-90deg) translateZ(56px);
}
}
}
}
</style>
示例-2
为了防止容器层处于2D平面,我们再加一层, 一下以codesandbox的cube loading为例
<template>
<div class="custom-wrapper">
<div class="container-2">
<div class="cube-2">
<div class="slides">
<div class="cube-item top" />
<div class="cube-item right" />
<div class="cube-item bottom" />
<div class="cube-item left" />
<div class="cube-item front" />
<div class="cube-item back" />
</div>
</div>
</div>
</div>
</template>
<style lang='scss' scoped>
.custom-wrapper {
--w: 100px;
@keyframes rotate {
0% {
transform: rotateX(-37.5deg) rotateY(45deg);
}
50% {
transform: rotateX(-37.5deg) rotateY(405deg);
}
100% {
transform: rotateX(-37.5deg) rotateY(405deg);
}
}
@keyframes top-animation {
0% {
opacity: 1;
transform: rotateX(90deg) translateZ(100px);
}
20% {
opacity: 1;
transform: rotateX(90deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateX(90deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateX(90deg) translateZ(100px);
}
100% {
opacity: 1;
transform: rotateX(90deg) translateZ(100px);
}
}
@keyframes bottom-animation {
0% {
opacity: 1;
transform: rotateX(-90deg) translateZ(100px);
}
20% {
opacity: 1;
transform: rotateX(-90deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateX(-90deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateX(-90deg) translateZ(100px);
}
100% {
opacity: 1;
transform: rotateX(-90deg) translateZ(100px);
}
}
@keyframes front-animation {
0% {
opacity: 1;
transform: rotateY(0deg) translateZ(var(--w));
}
20% {
opacity: 1;
transform: rotateY(0deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateY(0deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateY(0deg) translateZ(var(--w));
}
100% {
opacity: 1;
transform: rotateY(0deg) translateZ(var(--w));
}
}
@keyframes back-animation {
0% {
opacity: 1;
transform: rotateY(-180deg) translateZ(var(--w));
}
20% {
opacity: 1;
transform: rotateY(-180deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateY(-180deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateY(-180deg) translateZ(var(--w));
}
100% {
opacity: 1;
transform: rotateY(-180deg) translateZ(var(--w));
}
}
@keyframes left-animation {
0% {
opacity: 1;
transform: rotateY(-90deg) translateZ(var(--w));
}
20% {
opacity: 1;
transform: rotateY(-90deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateY(-90deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateY(-90deg) translateZ(var(--w));
}
100% {
opacity: 1;
transform: rotateY(-90deg) translateZ(var(--w));
}
}
@keyframes right-animation {
0% {
opacity: 1;
transform: rotateY(90deg) translateZ(var(--w));
}
20% {
opacity: 1;
transform: rotateY(90deg) translateZ(48px);
}
70% {
opacity: 1;
transform: rotateY(90deg) translateZ(48px);
}
90% {
opacity: 1;
transform: rotateY(90deg) translateZ(var(--w));
}
100% {
opacity: 1;
transform: rotateY(90deg) translateZ(var(--w));
}
}
.container-2 {
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
background-color: #151515;
padding: 60px 0;
height: 400px;
.cube-2 {
position: relative;
width: var(--w);
height: var(--w);
* {
width: var(--w);
height: var(--w);
position: absolute;
}
.slides {
animation: rotate 3s ease infinite;
animation-delay: 0.8s;
transform-style: preserve-3d;
transform: rotateX(-37.5deg) rotateY(45deg);
.cube-item {
border: 1px solid white;
border-radius: 8px;
background: rgba(white, 0.1);
}
.top {
animation: top-animation 3s ease infinite;
animation-delay: 0ms;
transform: rotateX(90deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
.bottom {
animation: bottom-animation 3s ease infinite;
animation-delay: 0ms;
transform: rotateX(-90deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
.front {
animation: front-animation 3s ease infinite;
animation-delay: 100ms;
transform: rotateY(0deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
.back {
animation: back-animation 3s ease infinite;
animation-delay: 100ms;
transform: rotateY(-180deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
.left {
animation: left-animation 3s ease infinite;
animation-delay: 100ms;
transform: rotateY(-90deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
.right {
animation: right-animation 3s ease infinite;
animation-delay: 100ms;
transform: rotateY(90deg) translateZ(var(--w));
animation-fill-mode: forwards;
transform-origin: 50% 50%;
}
}
}
}
}
</style>
示例-3
<script lang='ts' setup>
const classes = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
</script>
<template>
<div class="container">
<div class="cubescaler">
<div class="cube">
<div v-for="i in classes" :key="i" class="main" :class="i">
<div class="offset">
<div class="slide front" />
<div class="slide back" />
<div class="slide left" />
<div class="slide right" />
<div class="slide top" />
<div class="slide bottom" />
</div>
</div>
</div>
</div>
</div>
</template>
<style lang='scss' scoped>
@keyframes animation-b {
from {
transform: translate3d(83px, 46px, 0) scale(1);
opacity: 0;
}
33.33% {
transform: translate3d(53px, 26px, 0px) scale(1);
opacity: 1;
}
66.66% {
transform: matrix(1,0, 0, 1, 53, 26);
opacity: 1;
}
to {
transform: matrix(1,0, 0, 1, 53, 26);
opacity: 0;
}
}
@keyframes animation-c {
from {
transform: translate3d(-83px, 44px, 0);
opacity: 1;
}
33.33% {
transform: translate3d(-53px, 24px, 0px);
}
66.66% {
transform: translate3d(-53px, 24px, 0px) scale(1);
opacity: 1;
}
to {
transform: translate3d(-26px, 12px, 0px) scale(0.5);
opacity: 0;
}
}
.container {
--w: 75px;
--w-h: 37.5px;
--bg-color: rgba(102, 204, 51, 0.6);
position: relative;
width: 100%;
display: flex;
flex-direction: column;
background-color: #151515;
.cubescaler {
transform: matrix(0.75, 0, 0, 0.75, 0, 0);
}
.cube {
display: flex;
align-items: center;
position: relative;
width: 100%;
justify-content: center;
height: 250px;
.main {
position: absolute;
width: var(--w);
height: var(--w);
transform-style: preserve-3d;
will-change: transform;
transform-origin: 50% 50%;
.offset {
transform-style: preserve-3d;
will-change: transform;
transform-origin: 50% 50%;
transform: rotateY(48deg) rotateX(-20deg) rotateZ(-20deg);
* {
position: absolute;
width: var(--w);
height: var(--w);
background-color: var(--bg-color);
box-shadow: var(--bg-color) 0px;
border: 1px solid rgba(white, 0.6);
transform-origin: 50% 50%;
will-change: transform;
}
.top {
transform: rotateX(90deg) translateZ(var(--w-h));
}
.bottom {
transform: rotateX(-90deg) translateZ(var(--w-h));
}
.right {
transform: rotateY(0deg) translateZ(var(--w-h));
}
.left {
transform: rotateY(-180deg) translateZ(var(--w-h));
}
.front {
transform: rotateY(-90deg) translateZ(var(--w-h));
}
.back {
transform: rotateY(90deg) translateZ(var(--w-h));
}
}
&.b {
transform: matrix(1,0, 0, 1, 83, 46);
// transform: translate3d(53px, 26px, 0px);
animation: 1.8s ease-in-out infinite animation-b;
}
&.c {
transform: translate3d(-53px, 24px, 0px);
animation: 1.8s ease-in-out infinite animation-c;
}
&.d {
// transform: translate3d(0px, -84px, 0);
transform: translate3d(0px, -66px, 0px);
// opacity: 0;
}
&.e {
// transform: translate3d(0, 70px, 0);
transform: translate3d(0px, 50px, 0px);
// opacity: 0;
}
&.f {
// transform: translate3d(-72px, -62px, 0);
transform: translate3d(-52px, -42px, 0px);
// opacity: 0;
}
&.g {
// transform: translate3d(73px, -61px, 0);
transform: translate3d(53px, -41px, 0px);
// opacity: 0;
}
&.h {
// transform: translate3d(0px, -42px, 0);
transform: translate3d(0px, -16px, 0px);
// opacity: 0;
}
}
}
}
</style>
这个动画我写不好