前言
今天我们用前端 CSS 技术来做一个骰子。
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>投掷版本</title>
<style>
* {
padding: 0px;
margin: 0px;
}
body {
background: #000;
}
.sides-container {
perspective: 2000px; /* 定义 3D 元素距视图的距离 */
perspective-origin: 50% 50%; /* 定义 3D 元素所基于的 X 轴和 Y 轴 */
}
.sides {
width: 300px;
height: 300px;
position: relative;
transform-style: preserve-3d; /* 子元素将保留其 3D 位置 */
margin: 300px auto;
}
.side {
position: absolute;
width: 300px;
height: 300px;
padding: 20px;
border-radius: 20px;
background-color: #fff;
}
.point {
width: 60px;
height: 60px;
display: inline-block;
border-radius: 50%;
}
.point-red {
background-color: red;
}
.point-blue {
background-color: blue;
}
.side-one {
transform: translateZ(-340px);
display: flex;
justify-content: center;
align-items: center;
}
.side-two {
transform-origin: top;
transform: rotateX(-90deg);
display: flex;
justify-content: space-between;
align-items: center;
}
.side-three {
transform-origin: left;
transform: rotateY(90deg);
display: flex;
justify-content: space-between;
}
.side-three .point-two {
align-self: center;
}
.side-three .point-three {
align-self: flex-end;
}
.side-four {
transform-origin: right;
transform: rotateY(-90deg);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.side-four .column {
display: flex;
justify-content: space-between;
}
.side-five {
transform-origin: bottom;
transform: rotateX(90deg);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.side-five .column {
display: flex;
justify-content: space-between;
}
.side-five .two {
justify-content: center;
}
.side-six {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.side-six .column {
display: flex;
justify-content: space-around;
}
#throw-text {
color: #fff;
cursor: pointer;
}
</style>
</head>
<body>
<div id="throw-text">
开始投掷
</div>
<div class="sides-container">
<div class="sides">
<div class="side side-one">
<span class="point point-red"></span>
</div>
<div class="side side-two">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
<div class="side side-three">
<span class="point point-blue"></span>
<span class="point point-blue point-two"></span>
<span class="point point-blue point-three"></span>
</div>
<div class="side side-four">
<div class="column">
<span class="point point-red"></span>
<span class="point point-red"></span>
</div>
<div class="column">
<span class="point point-red"></span>
<span class="point point-red"></span>
</div>
</div>
<div class="side side-five">
<div class="column">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
<div class="column two">
<span class="point point-blue"></span>
</div>
<div class="column">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
</div>
<div class="side side-six">
<div class="column">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
<div class="column">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
<div class="column">
<span class="point point-blue"></span>
<span class="point point-blue"></span>
</div>
</div>
</div>
</div>
<script>
const getKeyframes = () => {
const getDeg = () => {
return Math.floor(Math.random() * 360);
};
const getTransform = percentage => {
return `${percentage}% {
transform: rotateY(${getDeg()}deg) rotateX(${getDeg()}deg);
}`;
};
const percentageList = [0, 20, 40, 60, 80, 100];
// 设置各关键帧骰子的转动位置
let keyframes = `@keyframes keyframes {`;
percentageList.forEach(percentage => {
keyframes += getTransform(percentage);
});
keyframes += "}";
return keyframes;
};
// 将关键帧样式添加到 html 中
const setKeyframesStyle = () => {
const keyframesStyleId = "keyframes";
const keyframesStyle = document.getElementById("keyframesStyleId");
if (keyframesStyle) {
keyframesStyle.remove();
}
const style = document.createElement("style");
style.id = keyframesStyleId;
style.innerText = getKeyframes();
document.getElementsByTagName("head")[0].appendChild(style);
};
document.getElementById("throw-text").addEventListener("click", () => {
setKeyframesStyle();
const sidesElement = document.getElementsByClassName("sides")[0];
const time = 0.5;
const count = 2;
// 设置动画
sidesElement.style.animation = `keyframes ${time}s linear 0s ${count}`;
setTimeout(() => {
sidesElement.style.animation = undefined;
}, time * count * 1000);
});
</script>
</body>
</html>
总结
涉及到的主要 CSS 知识有:
- 3D 视图(perspective)
- 2D/3D 转换(transform)
- flex 布局