带有 CSS 的幸运轮盘
我的推送里刚刚出现了一个“幸运轮盘”组件。我每次都转,但从来没赢过!总之,这类组件通常是用 CSS 实现的<canvas>,所以我决定写一篇教程,教大家如何用 CSS 制作。至于交互功能,还是需要用到 JavaScript。
我们将要建造的东西如下:
标记
对于楔形块,我们将使用一个简单的列表:
<ul class="wheel-of-fortune">
<li>$1000</li>
<li>$2000</li>
<li>$3000</li>
<li>$4000</li>
<li>$5000</li>
<li>$6000</li>
<li>$7000</li>
<li>$8000</li>
<li>$9000</li>
<li>$10000</li>
<li>$11000</li>
<li>$12000</li>
</ul>
好的,我们现在有了一系列数字。接下来,我们来设置一些初始样式:
:where(.ui-wheel-of-fortune) {
--_items: 12;
all: unset;
aspect-ratio: 1 / 1;
background: crimson;
container-type: inline-size;
direction: ltr;
display: grid;
place-content: center start;
}
首先,我们将使用一个变量来控制项目的数量。由于列表有 12 个项目,我们将其设置为 12 --_items: 12;。
我进行了设置,container-type以便我们可以使用容器查询单元(稍后会详细介绍),然后创建一个内容“左居中”的网格。这样我们就得到了:
好吧,看起来没什么特别的,我们来看看这些楔形块:
li {
align-content: center;
background: deepskyblue;
display: grid;
font-size: 5cqi;
grid-area: 1 / -1;
list-style: none;
padding-left: 1ch;
transform-origin: center right;
width: 50cqi;
}
position: absolute我们不使用“堆叠”的方式将所有元素堆叠<li>在网格的同一位置,而是将元素grid-area: 1 / -1设置为,这意味着我们将围绕该轴旋转楔形。transform-origincenter right
所以,现在我们有了:
因为所有元素都堆叠在一起,所以我们只能看到最后一个。
我们来解决这个问题。首先,我们给每个楔形区域添加一个索引变量:
li {
&:nth-of-type(1) { --_idx: 1; }
&:nth-of-type(2) { --_idx: 2; }
&:nth-of-type(3) { --_idx: 3; }
&:nth-of-type(4) { --_idx: 4; }
&:nth-of-type(5) { --_idx: 5; }
/* etc. */
}
这样我们只需要再添加一行CSS代码:
li {
rotate: calc(360deg / var(--_items) * calc(var(--_idx) - 1));
}
快完成了!让我们使用相同的变量来创建一些颜色变化:
li {
background: hsl(calc(360deg / var(--_items) *
calc(var(--_idx))), 100%, 75%);
}
π 的一片
要计算楔形块的高度,我们需要用圆的周长除以物品的数量。你可能还记得,圆的周长是:
C=2πr
因为我们使用的是容器单位,所以半径为0.0000 英寸50cqi,因此我们需要在 CSS 中使用以下公式:
li {
height: calc((2 * pi * 50cqi) / var(--_items));
}
现在CSS里有了π,是不是很酷?!
现在,我们给clip-path每个楔形区域添加一个简单的图形。我们从左上角开始,移动到右侧中心,然后再回到左下角:
li {
clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
}
让我们从边缘减去一些:
li {
clip-path: polygon(0% -2%, 100% 50%, 0% 102%);
}
不太确定,有没有数学上正确的方法来解决这个问题?
总之,现在我们只需要border-radius: 50%在包装器中添加以下内容:
嗯,不太好。我们改用 a clip-path,加上insetand round:
.wheel-of-fortune {
clip-path: inset(0 0 0 0 round 50%);
}
好多了:
因为我们对楔形和使用了容器单元,所以font-size它是完全响应式的!
让它旋转
现在,让我们添加一个旋转元素<button>(参见下方代码示例中的 CSS),并使用 JavaScript 触发该旋转元素:
function wheelOfFortune(selector) {
const node = document.querySelector(selector);
if (!node) return;
const spin = node.querySelector('button');
const wheel = node.querySelector('ul');
let animation;
let previousEndDegree = 0;
spin.addEventListener('click', () => {
if (animation) {
animation.cancel(); // Reset the animation if it already exists
}
const randomAdditionalDegrees = Math.random() * 360 + 1800;
const newEndDegree = previousEndDegree + randomAdditionalDegrees;
animation = wheel.animate([
{ transform: `rotate(${previousEndDegree}deg)` },
{ transform: `rotate(${newEndDegree}deg)` }
], {
duration: 4000,
direction: 'normal',
easing: 'cubic-bezier(0.440, -0.205, 0.000, 1.130)',
fill: 'forwards',
iterations: 1
});
previousEndDegree = newEndDegree;
});
}
我没有选择添加和删除 css 类并@property使用新的旋转角度更新,而是选择了最简单的解决方案:Web Animations API!
完整代码如下:
更新:形状大师 Temani Atif 提供了一种更优雅的方法来创建楔形
tan(aspect-ratio见下方评论)。
更多想法
我鼓励你尝试其他样式!比如添加虚线边框?
文章来源:https://dev.to/madsstoumann/wheel-of-fortune-with-css-p-pi-1ne9









