纯css实现九格宫抽奖

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

前言

JS写一个九格宫的抽奖程序并不难,但如果用css写呢?本文记叙了用css实现九格宫抽奖的过程。

效果

分析

把九格宫抽奖拆分一下,可以看成由两个部分组成:

  1. 奖品展示部分,抽奖的动画效果也是在这个部分完成;

这个部分除了展示奖品之外,还有一个抽奖的动画,当用户点击停止按钮时,停止动画,展示最终抽到的奖品,必须是一个奖品;

  1. 开始、停止按钮,供用户点击,决定什么时候停止抽奖。

按钮有两个状态,一个当前没有进行抽奖时,是开始按钮;当前进行抽奖时,是停止按钮。

代码

HTML布局

这个布局比较讲究,因为抽奖有两个状态:抽奖进行中抽奖停止。所以需要一个能在两个状态之间切换的元素,那就是<input type="checkbox" />,它有选中和没有选中两个状态,刚好对应的抽奖的两个状态。
那么要使input的选中状态能够影响抽奖动画,那么input必须是奖品元素的父级或者同级元素,又因为input需要伪装成按钮,所以本身要隐藏起来,借用别的元素进行伪装,所以只能是同级,布局如下:

<div class="box">
    <!-- 实际按钮 -->
    <input type="checkbox" id="btnInput" />
    <!-- 帮input伪装按钮 -->
    <label class="btn"></label>

    <!--奖品展示区域-->
    <div class="lattice">
      <div> 1 </div>
      <div> 2 </div>
      <div> 3 </div>
      <div> 4 </div>
      <div> 5 </div>
      <div> 6 </div>
      <div> 7 </div>
      <div> 8 </div>
      <div> 9 </div>
    </div>
  </div>
复制代码

css

  1. 奖品区域,本文是使用flex和一个伪元素,来实现九格宫和抽奖动画的。九格宫比较简单,不再赘述。

动画是借助一个::after,让其和每一个奖品的展示区域大小一样,然后不停的变换位置达到抽奖的效果。
而且位置变换时,不存在过度效果,这需要借助step-end或者step-start属性,它们可以让动画没有任何的过渡效果,在样式变化时直接展示改变后的效果。这样,无论在什么时候停下动画,都能确保选中一个奖品,样式如下:

.lattice::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 60px;
  height: 60px;
  background-color: red;
  /* 注意,这里设置了step-start */
  animation: displacement 1s infinite step-start;
}

/* 动画比较简单,就是不停改变位置 */
@keyframes displacement {
  0% {
    top: 0;
    left: 0;
  }
  11.1% {
    top: 0;
    left: 60px;
  }
  22.2% {
    top: 0;
    left: 120px;
  }
  33.3% {
    top: 60px;
    left: 0;
  }
  44.4% {
    top: 60px;
    left: 60px;
  }
  55.5% {
    top: 60px;
    left: 120px;
  }
  66.6% {
    top: 120px;
    left: 0;
  }
  77.7% {
    top: 120px;
    left: 60px;
  }
  88.8% {
    top: 120px;
    left: 120px;
  }
}
复制代码
  1. 然后就是按钮,<input>label伪装成按钮比较简单,就是将两个元素重叠在一起,把input的不透明度设置为零,然后将label伪装成按钮,层级设置成低于input,这样,用户以为是点击到label伪装的按钮,实际上是点击到input上,不再赘述。

但是本文是用label::after来伪装成按钮,因为可以使用content属性来更改按钮的文字,方便后续更改按钮的文字:

.btn::after {
  /* 按钮文字,后续可以用content直接修改 */
  content: '停止';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: #f59e0b;
  text-align: center;
  line-height: 40px;
  color: #fff;
}
复制代码

然后就是input被选中时,需要停止动画,这个时候就用到动画的状态属性animation-play-state,将其值改为paused,则动画就会停止下来,样式如下:

/* 因为input与展示奖品元素是同级,但不是相邻,所以使用普通兄弟选择器 */
#btnInput:checked ~ .lattice::after {
  /* 将动画状态该`paused`,停止动画 */
  animation-play-state: paused;
}
复制代码

同理,在input被选中时,更改按钮的文字:

扫描二维码关注公众号,回复: 14308715 查看本文章
#btnInput:checked + .btn::after {
  /* 通过content可以修改文字。这也是为什么选择用伪元素的原因 */
  content: '开始';
}
复制代码

猜你喜欢

转载自juejin.im/post/7109260859238514702