纯CSS-实现伪随机抽运势签

570 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

少年,你相信命吗?来抽一签看看吧🐶
最近学会利用CSS实现伪随机效果,在知道源码的情况下,是可以推测出结果的,但是在用户不知情的情况下,就等同于随机。

效果

基本思路

主要是伪随机的思路:利用动画animation不断将radio元素改变位置,而用户点击判定的区域是固定,但因为动画的原因,造成每一次点击都不一定是相同的radio,从而实现伪随机效果。
如下图,绿色为可点击区域,红色为不同radioradio不停的移动,造成每次选中的radio不一定相同:
动画.gif

代码

本文抽签效果中使用了10radio,一个是重置按钮,九个是待选的签,而这九个待选的签又分为三组, 全部的radio都是同一个name
因为要保证每次选中签之后,点击重置按钮可以获取新的结果,但是css中没有重置radio选中的功能,所以只能借助其另一个radio来实现重置。

  1. 重置按钮被选中的情况下,所有的签都执行动画,开始不停的改变自身的位置;如果重置按钮没有被选中,那么所有的签都停止动画,不再移动,将结果固定下来:
<!-- 默认选中重置按钮,让所有签执行动画,变换位置 -->
<input type="radio" id="resetBtn" name="label" checked="checked" />
<label for="resetBtn" class="reset-btn"> 重置 </label>
/* 重置按钮被选中时,其他radio都执行动画,改变位置 */
#resetBtn:checked ~ .labels .label {
  animation-play-state: running;
}

因为将所有的签原本的动画状态设置为animation-play-state: paused;,所以此处就不需要再写上没选中时停止动画的样式。
2. 剩下的九个radio分为三组,每组三个radio,分别代表大吉中吉小吉;然后将每组的radio从上到下位置进行排序,根据上面的伪随机思路进行移动。

注意:每组中签的移动不能像平时一样有过度状态的执行,那样可能会导致同一个点击区域,点击不同的位置,会出现不同的结果,所以必须给动画加上step-start或者step-end,让其按步骤执行。 其中一组布局如下:

<!-- 组 -->
<div class="labels labels-one">
  <!-- 大吉 -->
  <input type="radio" name="label" class="label very-lucky" />
  <!-- 中吉 -->
  <input type="radio" name="label" class="label lucky" />
  <!-- 小吉 -->
  <input type="radio" name="label" class="label little-lucky" />
  <!-- 用于显示被选中radio -->
  <div class="result"></div>
</div>

总体样式:

/* 标签组,同时也是可点击区域,设定位置、大小等 */
.labels {
  width: 60px;
  height: 100px;
  background-color: #fbbf24;
  overflow: hidden;
  border-radius: 5px;
  position: absolute;
  top: 10px;
}

/* 组中每一个标签,设定与可点击区域一样大,方便点击  */
.label {
  width: 60px;
  height: 100px;
  margin: 0;
  /* 添加动画,设置为无线循环,按步骤执行 */
  animation: roll 2s infinite step-end;
  /* 将动画设置为暂停状态,实现重置按钮的逻辑 */
  animation-play-state: paused;
  cursor: pointer;
  opacity: 0;
  position: relative;
  z-index: 10;
}

/* 位置改变动画 */
@keyframes roll {
  0% {
    transform: translateY(0);
  }
  33.33% {
    transform: translateY(-100px);
  }
  66.66% {
    transform: translateY(-200px)
  }
}


/* 显示结果,如果本组的签没有被选中时,显示默认文字 */
.result::after {
  content: '签';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  color: #ca8a04;
  text-align: center;
  line-height: 100px;
  font-weight: bold;
  font-size: 20px;
}

/* 组中不同radio被选中时,显示不同的结果 */
.very-lucky:checked ~ .result::after {
  content: '大吉';
}
.lucky:checked ~ .result::after {
  content: '中吉';
}
.little-lucky:checked ~ .result::after {
  content: '小吉';
}

上面是三组签中其中一组,至于其他组,为了保证随机,可以改变大吉中吉小吉三种类型的顺序,设置不同动画执行时间,不同动画延迟时间等等。
详细代码请参照上面码上掘金的示例。