更多有趣示例 尽在 知屋安砖社区
示例
HTML
<div class="container">
<div class="floor"></div>
<div class="table">
<div class="leg"></div>
<div class="leg"></div>
<div class="leg"></div>
<div class="leg"></div>
<div class="net">
<div class="top"></div>
<div class="left"></div>
<div class="right"></div>
</div>
<div class="front">Table tenniCSS - @Amit_Sheen</div>
<div class="back">Table tenniCSS - @Amit_Sheen</div>
<div class="left"></div>
<div class="right"></div>
</div>
<div class="ballWrapper">
<div class="ball"></div>
<div class="ballShadow"></div>
</div>
<div class="player player1">
<div class="playerBox">
<div class="top"></div>
<div class="left"></div>
<div class="right"></div>
<div class="back"></div>
<div class="ballShadow"></div>
<div class="shadow"></div>
</div>
</div>
<div class="player player2">
<div class="playerBox">
<div class="top"></div>
<div class="left"></div>
<div class="right"></div>
<div class="back"></div>
<div class="ballShadow"></div>
<div class="shadow"></div>
</div>
</div>
</div>
CSS
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@1,500&display=swap');
*, *::before, *::after {
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
$tablesize: 360px;
$playerSize: $tablesize * 0.1;
$color: #066;
$speed: 2.5s;
$ballSize: $tablesize * 0.0333;
$posCount: 16;
:root {
$a: 0;
@for $i from 0 to $posCount {
$a: ($a + 185) % 300;
--pos#{$i}: #{$a - 150}px;
}
}
body {
font-family: 'Montserrat', sans-serif;
background-color: #111;
color: #fff;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
perspective: $tablesize * 5;
perspective-origin: 40% calc(50% - #{$tablesize});
overflow: hidden;
}
.container {
position: absolute;
top: calc(50% + #{$tablesize * 0});
transform-style: preserve-3d;
animation: rotate $speed*32 linear infinite;
}
@keyframes rotate {
to { transform: rotateY(-360deg); }
}
.floor {
position: absolute;
width: 100vmax; height: 100vmax;
$floorColor: #afa3;
$floorSize: 40px;
background-image:
radial-gradient(#000d, #0000 33%, #111 66%),
repeating-linear-gradient($floorColor 0, transparent 1px $floorSize, $floorColor $floorSize+1px),
repeating-linear-gradient(to left, $floorColor 0, transparent 1px $floorSize, $floorColor $floorSize+1px)
;
transform: translate(-50%, -50%) rotateX(90deg) translateZ($tablesize * -0.5);
}
.leg {
position: absolute;
transform-style: preserve-3d;
transform: rotateX(-90deg);
transform-origin: top;
&:nth-child(1) { top: $tablesize * 0.1; left: $tablesize * 0.1; }
&:nth-child(2) { top: $tablesize * 0.1; right: $tablesize * 0.1; }
&:nth-child(3) { top: $tablesize * 0.9; left: $tablesize * 0.1; }
&:nth-child(4) { top: $tablesize * 0.9; right: $tablesize * 0.1; }
&::after {
content: '';
position: absolute;
top: $tablesize * 0.05; left: $tablesize * -0.05;
width: $tablesize * 0.1; height: $tablesize * 0.45;
background-image:
linear-gradient(#111, #1111),
linear-gradient(to left, #222, #777, #222);
border-radius: 0 0 50% 50% / 0 0 5px 5px;
animation: rotate $speed*32 linear infinite reverse;
}
}
.table {
position: absolute;
top: $tablesize * -0.5; left: $tablesize * -1;
height: $tablesize;
width: $tablesize * 2;
background-color: $color;
background-image:
radial-gradient(#fff1, #0003),
linear-gradient(to left, #fff 6px, #fff0 6px calc(100% - 6px), #fff calc(100% - 6px)),
linear-gradient(#fff 6px, #fff0 6px calc(50% - 3px), #fff calc(50% - 3px) calc(50% + 3px), #fff0 calc(50% + 3px) calc(100% - 6px), #fff calc(100% - 6px));
transform: rotateX(90deg);
transform-style: preserve-3d;
& > .net {
position: absolute;
width: 5%; height: 100%;
left: 50%;
transform: rotateY(-90deg);
transform-origin: left;
transform-style: preserve-3d;
background-image:
repeating-linear-gradient(45deg, #aaa 0 1px, #aaa0 1px 4px),
repeating-linear-gradient(135deg, #aaa 0 1px, #aaa0 1px 4px);
border: 2px solid #fff;
& > .top {
position: absolute;
top: 0; right: -1px;
width: 2px; height: 100%;
background-color: #ddd;
transform: rotateY(90deg);
}
& > .left {
position: absolute;
top: -1px; left: 0;
width: 100%; height: 2px;
background-color: #ccc;
transform: rotateX(90deg);
}
& > .right {
position: absolute;
bottom: -1px; left: 0;
width: 100%; height: 2px;
background-color: #ccc;
transform: rotateX(90deg);
}
}
& > .front {
position: absolute;
top: 100%; left: 0;
width: 100%; height: $tablesize * 0.05;
background-color: darken($color, 5%);
transform: rotateX(-90deg);
transform-origin: top;
}
& > .back {
position: absolute;
top: 0; left: 0;
width: 100%; height: $tablesize * 0.05;
background-color: darken($color, 5%);
transform: rotateX(-90deg) rotateY(180deg);
transform-origin: top;
}
& > .front, & > .back {
display: flex;
justify-content: center;
align-items: center;
font-size: $tablesize * 0.03;
color: #fff9;
}
& > .left {
position: absolute;
top: 0; left: 0;
width: $tablesize * 0.05; height: 100%;
background-color: darken($color, 10%);
transform: rotateY(90deg);
transform-origin: left;
}
& > .right {
position: absolute;
top: 0; right: 0;
width: $tablesize * 0.05; height: 100%;
background-color: darken($color, 10%);
transform: rotateY(-90deg);
transform-origin: right;
}
}
.ballWrapper {
position: absolute;
bottom: 1px;
transform-style: preserve-3d;
animation:
ballLeft $speed infinite cubic-bezier(.4,.5,.6,.6),
ballHeight $speed * 0.25 $speed * -0.875 infinite ease-in alternate,
ballZ $speed*$posCount*0.5 infinite cubic-bezier(.4,.5,.6,.6);
@keyframes ballLeft {
0%, 100% { left: #{$tablesize * -1 + $ballSize / 2}; }
50% { left: #{$tablesize - $ballSize / 2}; }
}
@keyframes ballHeight {
0% { height: #{$tablesize * 0.15}; }
100% { height: 0; }
}
@keyframes ballZ {
@for $i from 0 to $posCount {
$v1: '';
@if ($i == 0) {
$v1: ', 100%';
};
#{100% / $posCount * $i}#{$v1} { transform: translateZ(var(--pos#{$i})); }
}
}
.ball {
position: absolute;
top: $ballSize * -1; left: $ballSize * -0.5;
width: $ballSize; height: $ballSize;
background-color: #fff;
background-image: radial-gradient(circle at 50% 10%, #fff, #333);
border-radius: 50%;
animation: rotate $speed*32 linear infinite reverse;
}
.ballShadow {
position: absolute;
bottom: 0; left: 0;
width: $ballSize*3;
height: $ballSize*3;
background-image: radial-gradient(#000, #0000 50%);
transform: rotateX(-90deg) translateY($ballSize * -1);
animation: ballShadowTransform $speed * 0.25 $speed * -0.875 infinite ease-in alternate;
@keyframes ballShadowTransform {
from { transform: translate(-50%, 50%) rotateX(90deg) scale(4); opacity: 0.1; }
to { transform: translate(-50%, 50%) rotateX(90deg) scale(1); opacity: 0.6; }
}
}
}
.player {
position: absolute;
top: 0;
width: $playerSize; height: $playerSize;
transform: rotateY(90deg);
transform-style: preserve-3d;
}
.player1 {
left: $tablesize;
animation: player1Pos $speed*$posCount*0.5 infinite ease-in-out;
@keyframes player1Pos {
@for $i from 0 to ceil($posCount/2) {
$v1: ''; $v2: '';
@if ($i < $posCount/2) {
$v1: ', #{100% / $posCount * ($i + 1) * 2}';
}
@if ($i == ($posCount/2 - 1)) {
$v2: ', 0%';
}
#{100% / $posCount * ($i + 0.5) * 2}#{$v1}#{$v2} { transform: rotateY(-90deg) translateX(var(--pos#{$i*2+1})) translateY($playerSize * -1.7) translateZ(#{$playerSize * 0.5}); }
}
}
& > .playerBox {
background-color: #903;
animation-delay: $speed * -0.5;
}
}
.player2 {
right: $tablesize;
animation: player2Pos $speed*$posCount*0.5 infinite ease-in-out;
@keyframes player2Pos {
@for $i from 0 to ceil($posCount/2) {
$v1: ''; $v2: '';
@if ($i < $posCount/2) {
$v1: ', #{100% / $posCount * ($i + 0.5) * 2}';
}
@if ($i == 0) {
$v2: ', 100%';
}
#{100% / $posCount * $i * 2}#{$v1}#{$v2} { transform: rotateY(90deg) translateX(calc(var(--pos#{$i*2}) * -1)) translateY($playerSize * -1.7) translateZ(#{$playerSize * 0.5}); }
}
}
& > .playerBox {
background-color: #039;
}
}
.playerBox {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-image: linear-gradient(#0000, #0004);
transform-style: preserve-3d;
animation: playerHit $speed infinite ease-in;
@keyframes playerHit {
0%, 90%, 100% { transform: translateZ(0); }
96.66% { transform: translateZ(#{$playerSize * -1}); }
}
.top {
position: absolute;
top: 0; left: 0;
width: 100%; height: $playerSize * 0.25;
background-color: inherit;
transform: rotateX(-90deg);
transform-origin: top;
}
.left {
position: absolute;
top: 0; left: 0;
width: $playerSize * 0.25; height: 100%;
background-color: inherit;
background-image: linear-gradient(#0000, #0007);
transform: rotateY(90deg);
transform-origin: left;
}
.right {
position: absolute;
top: 0; right: 0;
width: $playerSize * 0.25; height: 100%;
background-color: inherit;
background-image: linear-gradient(#0000, #0007);
transform: rotateY(-90deg);
transform-origin: right;
}
.back {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: inherit;
background-image: linear-gradient(#0000, #0004);
transform: translateZ($playerSize * -0.25);
}
.shadow {
position: absolute;
top: 0; left: 50%;
width: 300%; height: 100%;
background-image: radial-gradient(at top, #0003, #0000 50%);
transform-origin: top;
animation: playerShadow $speed infinite ease-in;
animation-delay: inherit;
@keyframes playerShadow {
0%, 90%, 100% { transform: translate(-50%, $playerSize * 1.7) rotateX(90deg); opacity: 1; }
96.66% { transform: translate(-50%, $playerSize * 1.7) rotateX(90deg) translateY($playerSize * 1); opacity: 0; }
}
}
.ballShadow {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-image: radial-gradient(circle at 50% 75%, #0007, #0000 25%);
background-size: 100% 200%;
background-repeat: no-repeat;
animation: playerBallShadow $speed infinite ease-in;
animation-delay: inherit;
@keyframes playerBallShadow {
0%, 100% { background-position-y: 100%; opacity: 1; }
5%, 85% { background-position-y: 0%; opacity: 0; }
}
}
}