CSS Roulette Wheel

Addictive and Easy to Use
CSS Animated Wheel Module Imitating Roulette

Make Decisions with Style Using Only HTML and CSS

In today's article, I'd like to present a randomizing module in the form of a pie chart, which in its simplest form can be called a roulette wheel. This component is highly addictive, and in the version presented below, it makes it easier to make difficult decisions. This module is an animated wheel, controlled using the pseudo-element :checked, which when a input element is selected, stops pointing to the drawn position. The clear advantage of the module is the ease of adding new positions, as well as a pre-defined maximum of twenty fields, which can easily be increased.

To place the roulette wheel on the target website, simply copy the HTML code of the module, available below in the index.html tab. Place it in any location in your HTML document. Then, perform the same operation with the neighboring CSS tab, copying its contents to our stylesheet. The module editing instructions are located below the demo:

<div class="compsoul-body">
  <input class="compsoul-roulette-checkbox hidden" id="compsoul-roulette-checkbox" type="checkbox" name="compsoul-roulette-checkbox">
  <label class="compsoul-roulette-label" for="compsoul-roulette-checkbox"></label>
  <div class="compsoul-roulette">
    <ul class="roulette-list">
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">GO TO WORK</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
      <li class="roulette-item">Go for a beer</li>
    </ul>
    <div class="roulette-marker"></div>
  </div>
</div>
.hidden {
  border: 0 !important;
  height: 1px !important;
  opacity: 0;
  overflow: hidden;
  padding: 0 !important;
  pointer-events: none;
  position: absolute !important;
  width: 1px !important;
}

.compsoul-body {
  align-items: center;
  background: #2f8f9d;
  display: flex;
  flex-flow: column wrap;
  font-size: 1.125vw;
  padding: 6vw;
}

.compsoul-roulette-label {
  background: #181818;
  color: #ffffff;
  cursor: pointer;
  font-family: Helvetica, Arial, sans-serif;
  font-weight: 200;
  padding: 0.8vw 1.2vw;
  margin: 0 0 3.2vw;
  text-transform: uppercase;
}

.compsoul-roulette-label:before {
  content: "Try your luck";
}

.compsoul-roulette-checkbox:checked + .compsoul-roulette-label:before {
  content: "Stop!";
}

.compsoul-roulette {
  --size: 34em;
  --number-of-items: 12;

  --angle: calc( 3.1416 / var(--number-of-items) );
  --tangent-first: var(--angle);
  --tangent-second: calc( (1/3) * var(--angle) * var(--angle) * var(--angle) );
  --tangent-third: calc( (2 / 15) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) );
  --tangent-fourth: calc( (17/315) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) * var(--angle) );
  --tangent: calc( var(--tangent-first) + var(--tangent-second) + var(--tangent-third) + var(--tangent-fourth) );

  outline: 1.2em solid #fff;
  outline-offset: -1em;
  border-radius: 100%;
  box-shadow: 1.2em 1.2em 0 -0.8em #00000022;
  height: var(--size);
  position: relative;
  width: var(--size);
  z-index: 1;
}

.compsoul-roulette:before,
.compsoul-roulette:after {
  background: #00000022;
  border-radius: 100%;
  content: "";
  height: 8em;
  left: 50%;
  position: absolute;
  top : 50%;
  transform: translate(-45%, -45%);
  width: 8em;
  z-index: 2;
}

.compsoul-roulette:after {
  background: #ffffff url("https://compsoul.pl/uploads/images/logo.svg") no-repeat center;
  background-size: 80%;
  transform: translate(-50%, -50%);
  z-index: 2;
}

.compsoul-roulette .roulette-marker {
  border-radius: 0.4em 0 0 0.4em;
  left: -2em;
  overflow: hidden;
  position: absolute;
  top: 50%;
  transform: translate(0, -50%);
  z-index: 0;
}

.compsoul-roulette .roulette-marker:before,
.compsoul-roulette .roulette-marker:after {
  border-bottom: 2em solid transparent;
  border-left: 4em solid #ffa3c7;
  border-top: 2em solid transparent;
  content: "";
  display: block;
  height: 0;
  width: 0;
}

.compsoul-roulette .roulette-marker:after {
  border-left: 4em solid #00000022;
  position: absolute;
  top: 0.4em;
  z-index: -1;
}

.compsoul-roulette .roulette-list {
  animation: roulette 0.8s linear infinite paused;
  border-radius: 100%;
  font-family: Helvetica, Arial, sans-serif;
  height: 100%;
  list-style-type: none;
  margin: 0;
  overflow: hidden;
  padding: 0;
  position: relative;
  width: 100%;
  z-index: -1;
}

.compsoul-roulette-checkbox:checked + .compsoul-roulette-label + .compsoul-roulette .roulette-list {
  animation-play-state: running;
}

@keyframes roulette {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

.compsoul-roulette .roulette-item {
  align-items: center;
  bottom: calc( var(--size) / 2 );
  color: #ffffff;
  display: flex;
  font-size: 1em;
  font-weight: 600;
  height: calc( var(--size) / 2 );
  left: calc( var(--size) / 4 );
  position: absolute;
  text-indent: 2em;
  text-transform: uppercase;
  transform-origin: bottom center;
  width: calc( var(--size) / 2 );
  writing-mode: vertical-rl;
}

.compsoul-roulette .roulette-item:nth-child(1) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 0 ) );
}

.compsoul-roulette .roulette-item:nth-child(2) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 1 ) );
}

.compsoul-roulette .roulette-item:nth-child(3) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 2 ) );
}

.compsoul-roulette .roulette-item:nth-child(4) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 3 ) );
}

.compsoul-roulette .roulette-item:nth-child(5) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 4 ) );
}

.compsoul-roulette .roulette-item:nth-child(6) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 5 ) );
}

.compsoul-roulette .roulette-item:nth-child(7) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 6 ) );
}

.compsoul-roulette .roulette-item:nth-child(8) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 7 ) );
}

.compsoul-roulette .roulette-item:nth-child(9) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 8 ) );
}

.compsoul-roulette .roulette-item:nth-child(10) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 9 ) );
}

.compsoul-roulette .roulette-item:nth-child(11) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 10 ) );
}

.compsoul-roulette .roulette-item:nth-child(12) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 11 ) );
}

.compsoul-roulette .roulette-item:nth-child(13) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 12 ) );
}

.compsoul-roulette .roulette-item:nth-child(14) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 13 ) );
}

.compsoul-roulette .roulette-item:nth-child(15) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 14 ) );
}

.compsoul-roulette .roulette-item:nth-child(16) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 15 ) );
}

.compsoul-roulette .roulette-item:nth-child(17) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 16 ) );
}

.compsoul-roulette .roulette-item:nth-child(18) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 17 ) );
}

.compsoul-roulette .roulette-item:nth-child(19) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 18 ) );
}

.compsoul-roulette .roulette-item:nth-child(20) {
  transform: rotate( calc( 360deg / var(--number-of-items) * 19 ) );
}

.compsoul-roulette .roulette-item:after {
  bottom: 0;
  border-right: calc( var(--size) / 2 * var(--tangent) + 1px ) solid transparent;
  border-top: calc( var(--size) / 2 ) solid transparent;
  border-left: calc( var(--size) / 2 * var(--tangent) + 1px ) solid transparent;
  content: "";
  display: block;
  height: 0;
  left: 50%;
  position: absolute;
  transform: translate(-50%, 0);
  width: 0;
  z-index: -1;
}

.compsoul-roulette .roulette-item:nth-child(4n+1):after {
  border-top-color: #143f6b;
}

.compsoul-roulette .roulette-item:nth-child(4n+2):after {
  border-top-color: #F1E0AC;
}

.compsoul-roulette .roulette-item:nth-child(4n+3):after {
  border-top-color: #F55353;
}

.compsoul-roulette .roulette-item:nth-child(4n+4):after {
  border-top-color: #feb139;
}
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • GO TO WORK
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • Go for a beer
  • Go for a beer

The basic editing of the roulette module's functionality is done by editing two variables:

  • size - a variable responsible for editing the size of the wheel. In the presented example, I used em units, but we can easily convert them to any unit by appropriately converting the entire code.
  • number-of-items - a variable responsible for the number of elements inside the wheel. The maximum number of positions that we can add inside the circle has been set to twenty elements. However, we can adjust it to our needs by appropriately editing the CSS code.

I encourage you to play and test the module! It works great as a friendly addition when drawing promotions in an online store after adding the appropriate JS scripts.

P.S. I'm going for a beer. Fate has willed it.