Posted in css
424
11:08 pm, March 3, 2026
 

Roulette wheel with CSS random() - Safari / WebKit browsers only

seems to not be random, but it does spin...

HTML

<section class="wrapper">
  <input type="checkbox" id="radio-spin">
  <div class="controls">
    <label for="radio-spin">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-label="Spin the Wheel" title="Spin the Wheel">
          <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
          <path d="M14 12a2 2 0 1 0 -4 0a2 2 0 0 0 4 0" />
          <path d="M12 21c-3.314 0 -6 -2.462 -6 -5.5s2.686 -5.5 6 -5.5" />
          <path d="M21 12c0 3.314 -2.462 6 -5.5 6s-5.5 -2.686 -5.5 -6" />
          <path d="M12 14c3.314 0 6 -2.462 6 -5.5s-2.686 -5.5 -6 -5.5" />
          <path d="M14 12c0 -3.314 -2.462 -6 -5.5 -6s-5.5 2.686 -5.5 6" />
      </svg>

      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-label="Reset the Wheel" title="Reset the Wheel">
        <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
        <path d="M3.06 13a9 9 0 1 0 .49 -4.087" />
        <path d="M3 4.001v5h5" />
        <path d="M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
      </svg>
    </label>
  </div>
  
  <div id="wheel" class="wheel">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </div>
</section>
<section class="notes">
  <p>Sorry, your browser doesn't support CSS <code>random()</code> so it will default to a non-random value. <br>Please try this on Safari to see the function working.</p>
  
  <p>This demo uses the experimental CSS function <code>random()</code>, which is currently supported only in Safari / WebKit browsers.</p>

<p>Because of how <code>random()</code> works, its value is calculated once when the page styles are first evaluated.
That means the wheel does not generate a new random result on every spin — <strong>the same value is reused until the page is refreshed.</strong>
<br>
This is a limitation of the current implementation rather than the concept itself. Future browser updates and specification changes may allow <code>random()</code> to be recalculated dynamically (but I wouldn't count on it).</p>
</section>

CSS

@import url(https://fonts.bunny.net/css?family=jura:300,700);
@layer base,notes, demo;

@layer demo{
  :root{
    --items: 12;
    --spin-easing: cubic-bezier(0, 0.061, 0, 1.032);
    /* define angles for wheel background gradient */
    --slice-angle: calc(360deg / var(--items));
    --start-angle: calc(var(--slice-angle) / 2);

    --wheel-radius: min(40vw, 300px);
    --wheel-size: calc(var(--wheel-radius) * 2);
  	--wheel-padding: 10%;
  	--item-radius: calc(var(--wheel-radius) - var(--wheel-padding));

    /* bacgkround colors for wheel */
    --wheel-bg-1: oklch(0.80 0.16 30);
    --wheel-bg-2: oklch(0.74 0.16 140);
    --wheel-bg-3: oklch(0.80 0.16 240);
    --wheel-bg-4: oklch(0.74 0.16 320);

    --marker-bg-color: black;
    --button-text-color: white;

    --spin-duration: 2s;
    --random-angle: 4800deg;
    /* browsers that don't support random() will have a fixed value so that they can at least see the wheel spinning */
    @supports  (rotate: random(1deg, 10deg)) {
     /* random values - Safari only */
			/* duration of the spin to add randomness */
    	--spin-duration: random(1000ms, 3000ms);
    
    	/* The optional 3rd value (step) ensures that it stops at the center of an option */
    	--random-angle: random(1200deg, 4800deg, var(--slice-angle));

    }
  }
  

  .wrapper {
    position: relative;
    inset: 0;
    margin: auto;
    width: var(--wheel-size);
    aspect-ratio: 1;
    
    /* hide checkbox */
    input[type=checkbox]{
      position: absolute;
      opacity: 0;
      width: 1px; 
      height: 1px;
      pointer-events: none;
    }
    /* checked - udpate vars for wheel and controls */
    &:has(input[type=checkbox]:checked){
      --spin-it: 1;
      --btn-spin-scale: 0;
      --btn-spin-event: none;
      --btn-spin-trans-duration:var(--spin-duration);
      --btn-reset-scale: 1;
      --btn-reset-event: auto;
      --btn-reset-trans-delay: var(--spin-duration);
    }
  
    /* center of wheel buttons and marker */
    .controls{
      position: absolute;
      z-index: 2;
      inset:0;
      margin: auto;
      width: min(100px,10vw);
      aspect-ratio: 1;
      background: var(--marker-bg-color);
      border-radius: 9in;
      transition: scale 150ms ease-in-out;
      
      &:has(:hover,:focus-visible) label{
        scale: 1.2;
        rotate: 20deg;
      }
      /* marker */
      &::before{
        content: '';
        position: absolute;
        top:0;
        left: 50%;
        translate: -50% -50%;
        width: 20%;
        aspect-radio: 2/10;
        background-color: transparent;
        border:2vw solid var(--marker-bg-color);
        border-bottom-width: 4vw;
        border-top: 0;
        border-left-color: transparent;
        border-right-color: transparent;
        z-index: -1;
      }
     /* spin & reset buttons */
      label{
        cursor: pointer;
        display: grid;
        place-items: center;
        width: 100%;
        aspect-ratio: 1;
        color: var(--button-text-color);
        transition: 
          rotate 150ms ease-in-out, 
          scale 150ms ease-in-out;
        svg{
          grid-area: 1/1;
          width: 50%;
          height: 50%;
          transition-property: scale;
          transition-timing-function: ease-in-out;
          &:first-child{
            transition-duration: var(--btn-spin-trans-duration,150ms); /* slow scale down when spinning */
            scale: var(--btn-spin-scale,1);
            pointer-events: var(--btn-spin-event,auto);
          }
          &:last-child{
            transition-duration: 150ms;
            transition-delay: var(--btn-reset-trans-delay,0ms); /* delay scale up when spinning */
            scale: var(--btn-reset-scale,0);
            pointer-events: var(--btn-reset-event,none);
          }
        }
      }
			
			
    }
		&:has(input[type=checkbox]:checked){
			> .wheel{
				animation: --spin-wheel var(--spin-duration,3s) var(--spin-easing,ease-in-out) forwards;
				
			}
			.controls::before{
					animation: --marker 100ms ease-in-out;
					animation-iteration-count: 15;
				}
		}
     
    .wheel {
      position: absolute;
      inset: 0;
      border-radius: 99vw;
      border: 1px solid white;
      user-select: none;
      background: repeating-conic-gradient(
        from var(--start-angle),
        var(--wheel-bg-1) 0deg var(--slice-angle),
        var(--wheel-bg-2) var(--slice-angle) calc(var(--slice-angle) * 2),
        var(--wheel-bg-3) calc(var(--slice-angle) * 2) calc(var(--slice-angle) * 3),
        var(--wheel-bg-4) calc(var(--slice-angle) * 3) calc(var(--slice-angle) * 4)
      );
      /*
			style query to spin wheel  --spin-it value is toggled by checkbox 
			I opted to use the simpler :checked and sibling selector as Firefox doesn't yet sypport style queries apparantly
			*/
      @container style(--spin-it:1){
        /*animation: --spin-wheel var(--spin-duration,3s) var(--spin-easing,ease-in-out) forwards;*/
			
      }

      /* numbers */
      > span{
        --i: sibling-index();
        @supports not (sibling-index(0)) { 
    				&:nth-child(1){ --i: 1;}
    				&:nth-child(2){ --i: 2;}
    				&:nth-child(3){ --i: 3;}
    				&:nth-child(4){ --i: 4;}
    				&:nth-child(5){ --i: 5;}
    				&:nth-child(6){ --i: 6;}
    				&:nth-child(7){ --i: 7;}
    				&:nth-child(8){ --i: 8;}
    				&:nth-child(9){ --i: 9;}
    				&:nth-child(10){ --i: 10;}
    				&:nth-child(11){ --i: 11;}
    				&:nth-child(12){ --i: 12;}
    		}
    		
        position: absolute;
    		font-size: clamp(1.2rem, 4.5vw + 0.045rem, 3rem);
        offset-path: circle(var(--item-radius) at 50% 50%);
     		offset-distance: calc(var(--i) / var(--items) * 100%);
        offset-rotate: auto;
        &::after{
          content: counter(c);
          counter-reset: c var(--i);
        }
      }
    }
  }
  @keyframes --spin-wheel {
    to {
      rotate: var(--random-angle);
    }
  }
	@keyframes --marker{
		25%{ rotate:8deg}
		75%{ rotate:0deg
		}
	}
}

@layer notes{
  section.notes{
    margin: auto;
    width: min(80vw, 56ch);
    p{
      text-wrap:pretty;
    }
    > :first-child{
      color: red;
      background: rgb(255, 100, 103);
      padding: .5em;
      color: white;
      @supports  (rotate: random(1deg, 10deg)) {
          display: none;
      }
    }
  }
}

@layer base{
  *,::before,::after{
  	box-sizing: border-box;
  }
	:root {
		color-scheme: light dark;
		--bg-dark: rgb(21 21 21);
		--bg-light: rgb(248, 244, 238);
		--txt-light: rgb(10, 10, 10);
		--txt-dark: rgb(245, 245, 245););
		--line-light: rgba(0 0 0 / .75);
		--line-dark: rgba(255 255 255 / .25);

    --clr-bg: light-dark(var(--bg-light), var(--bg-dark));
    --clr-txt: light-dark(var(--txt-light), var(--txt-dark));
    --clr-lines: light-dark(var(--line-light), var(--line-dark));
	}
  body {
		background-color: var(--clr-bg);
		color: var(--clr-txt);
		min-height: 100svh;
		margin: 0;
		padding: 2rem;
		font-family: "Jura", sans-serif;
		font-size: 1rem;
		line-height: 1.5;
    display: grid;
    place-content: center;
    gap: 2rem;
  }
  strong{
    font-weight: 700;
  }
}

Sorry, your browser doesn't support CSS random() so it will default to a non-random value.
Please try this on Safari to see the function working.

This demo uses the experimental CSS function random(), which is currently supported only in Safari / WebKit browsers.

Because of how random() works, its value is calculated once when the page styles are first evaluated. That means the wheel does not generate a new random result on every spin — the same value is reused until the page is refreshed.
This is a limitation of the current implementation rather than the concept itself. Future browser updates and specification changes may allow random() to be recalculated dynamically (but I wouldn't count on it).

External Link for Roulette wheel with CSS random() - Safari / WebKit browsers only

View Statistics
This Week
7
This Month
88
This Year
229

No Items Found.

Add Comment
Type in a Nick Name here
 
Other Items in css
Roulette wheel with CSS random() - Safari / WebKit browsers only nice mini box zoom on hover css Stop Deleting HTML! Using CSS :nth-child to Hide List Items Stop Using Position Absolute to Center Divs (Do This Instead) The CSS Unit You’re Not Using: VMAX Explained 📐 Stop Using Pixels! Use VW for Responsive CSS 🚀 CSS Backdrop-Filter Blur: Add a Stunning Blur to Any Background Overlay (Too Easy!) Fix Jaggy Font Edges with CSS Font Smoothing and Antialiasing CSS 4 box custom grid row - New Version - July 2025 override the hero image background on this page Striped Background Gradients in CSS + HTML Changing the Background in CSS Using accent-color to change check box color Making an image responsive using css using background cover flex to align pagination in list format make an image or element grayscale switch on mouse over rotate an element when its hover rotate an element when its selected Left Fixed nav with right fluid content css html vertical center css cursor types testing CSS Object Fit for Image fill rather than using background image on a div flip card animation 3d front and back css html six box grid css html custom no gap four box grid css html custom Kinda Crappy 3D button code 4 box custom grid css layout stack on mobile 1024 lower use an image in your list items ol ul li css grid container with 4 auto columns select something with custom data attribute css rainbow text background clip with linear gradient content-visibility and contain-intrinsic-size for page load rendering speed increase set a css grid to auto to make it stack on mobile truncate text with line clamp allow a certain number of lines using the :user-valid CSS pseudo-class add a button to an existing link using :after css bouncing loader animation in css center a box in the middle of the screen highlight a button with an animation css add an outline to everything! hide the first h3 tag on the page with css center align vertical 2 items in a container flex simple javascript no library accordion button zoom effect with expanding background scroll left animation using css counter-increment to add numbering to elements hidden scroll anchor for custom scroll position ken burns slow image zoom using a radial gradient for background overlay change selected color on input elements css
Search Code
Search Code by entering your search text above.
Welcome

This is my test area for webdev. I keep a collection of code here, mostly for my reference. Also if i find a good link, i usually add it here and then forget about it. more...

You could also follow me on twitter. I have a couple of youtube channels if you want to see some video related content. RuneScape 3, Minecraft and also a coding channel here Web Dev.

If you found something useful or like my work, you can buy me a coffee here. Mmm Coffee. ☕

❤️👩‍💻🎮

🪦 2000 - 16 Oct 2022 - Boots
Random Quote
When I realized that, no individual step is hard in any process. Building this airport I'm standing in right now started with a guy writing the architectural plans on paper. That's not hard for him to do. Then laying the first beam isn't had. The whole thing is really hard. So, just take each step kind of piece by piece and when I was able to do that and stop trying to chase this prize and started putting in the work, things just started coming together.
Unknown
Latest News
## 🚀 AI Giants Hit Bullseye: Anthropic & OpenAI Achieve Product-Market Fit Anthropic and OpenAI have reached a significant milestone, finding product-market fit with their AI technologies, which means their products effectively meet the needs of their customers, driving growth and adoption. This achievement showcases the practical value of their innovations, enabling businesses and individuals to leverage AI for enhanced productivity and efficiency. With this alignment of product and market needs, these companies are poised to transform industries and shape the future of technology.