29

I am wondering if it is possible to do something like this with css gradients:

color wheel

I have searched a lot and all the gradients are either "Linear" or "Radial". My desired gradient is linear in a circular way!

4
  • Interesting question. But I think it's not possible using just a CSS gradient.
    – GolezTrol
    Commented Jul 15, 2015 at 7:01
  • 1
    I came up with a messy solution with css & javascript. I can create many circle slices and color them. But I don't think it's the way to go. Commented Jul 15, 2015 at 7:10
  • Actually, that's the best way I can think of using pure CSS.
    – Purag
    Commented Jul 15, 2015 at 7:15
  • 1
    This is very highly difficult with CSS. Would be easy with Canvas or SVG. Have a look at my answer here for SVG/Canvas implementation. There are also other SVG and CSS (conical gradient) answers which you would find helpful.
    – Harry
    Commented Jul 15, 2015 at 7:50

7 Answers 7

20

-- Updated with information from early 2022 --

It's doable now - at least with most browsers. The CSS property conic-gradient can easily achieve this:

html, body { margin: 0; padding: 0; }
.box {
    position: absolute;
    width: 200px;
    height: 200px;
    left: 100px;
}
.colorwheel {
    background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
    border-radius:50%;
}
.fallback {
    text-align: center;
    padding: 50px 0;
}
<div class="fallback box">
    If you can read<br>this, your browser<br>doesn't support<br>conic-gradient yet.
</div>
<div class="colorwheel box"></div>

This CSS function is specified in an editor's draft of CSS Images Module Level 4 and is currently implement by most browsers including many mobile browsers. Check Can I use for current support.

6

This is called Conical Gradient and is not currently possible in pure CSS, but it has been proposed for the CSS Image Values 4 draft. Recently Lea Verou created a polyfill for them, there is also a PostCSS plugin that does the same.

6

CSS

This can be completed using multiple sections which are then rotated to create a circle.

.wheel,
.umbrella,
.color {
  content: "";
  position: absolute;
  border-radius: 50%;
  width: 15em;
  height: 15em;
  margin: 0;
  padding: 0;
}
.wheel {
  overflow: hidden;
  width: 15em;
  height: 15em;
  position: relative;
}
.umbrella {
  position: relative;
  -webkit-transform: scale(1.35);
}
.color,
.color:nth-child(n+7):after {
  clip: rect(0, 15em, 15em, 7.5em);
}
.color:after,
.color:nth-child(n+7) {
  content: "";
  position: absolute;
  border-radius: 50%;
  left: calc(50% - 7.5em);
  top: calc(50% - 7.5em);
  width: 15em;
  height: 15em;
  clip: rect(0, 7.5em, 15em, 0);
}
.color:nth-child(1):after {
  background-color: #9ED110;
  transform: rotate(30deg);
  z-index: 12;
}
.color:nth-child(2):after {
  background-color: #50B517;
  transform: rotate(60deg);
  z-index: 11;
}
.color:nth-child(3):after {
  background-color: #179067;
  transform: rotate(90deg);
  z-index: 10;
}
.color:nth-child(4):after {
  background-color: #476EAF;
  transform: rotate(120deg);
  z-index: 9;
}
.color:nth-child(5):after {
  background-color: #9f49ac;
  transform: rotate(150deg);
  z-index: 8;
}
.color:nth-child(6):after {
  background-color: #CC42A2;
  transform: rotate(180deg);
  z-index: 7;
}
.color:nth-child(7):after {
  background-color: #FF3BA7;
  transform: rotate(180deg);
}
.color:nth-child(8):after {
  background-color: #FF5800;
  transform: rotate(210deg);
}
.color:nth-child(9):after {
  background-color: #FF8100;
  transform: rotate(240deg);
}
.color:nth-child(10):after {
  background-color: #FEAC00;
  transform: rotate(270deg);
}
.color:nth-child(11):after {
  background-color: #FFCC00;
  transform: rotate(300deg);
}
.color:nth-child(12):after {
  background-color: #EDE604;
  transform: rotate(330deg);
}
<div class="wheel">
  <ul class="umbrella">
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
  </ul>
</div>

To then get the blur, just use the transform function to add an appropriate blur.

.wheel,
.umbrella,
.color {
  content: "";
  position: absolute;
  border-radius: 50%;
  width: 15em;
  height: 15em;
  margin: 0;
  padding: 0;
}
.wheel {
  overflow: hidden;
  width: 15em;
  height: 15em;
  position: relative;
}
.umbrella {
  position: relative;
  filter: blur(.75em);
  -webkit-filter: blur(.75em);
  -moz-filter: blur(.75em);
  -o-filter: blur(.75em);
  -ms-filter: blur(.75em);
  filter: url(#blur);
  filter: progid: DXImageTransform.Microsoft.Blur(PixelRadius='.75');
  -webkit-transform: scale(1.35);
}
.color,
.color:nth-child(n+7):after {
  clip: rect(0, 15em, 15em, 7.5em);
}
.color:after,
.color:nth-child(n+7) {
  content: "";
  position: absolute;
  border-radius: 50%;
  left: calc(50% - 7.5em);
  top: calc(50% - 7.5em);
  width: 15em;
  height: 15em;
  clip: rect(0, 7.5em, 15em, 0);
}
.color:nth-child(1):after {
  background-color: #9ED110;
  transform: rotate(30deg);
  z-index: 12;
}
.color:nth-child(2):after {
  background-color: #50B517;
  transform: rotate(60deg);
  z-index: 11;
}
.color:nth-child(3):after {
  background-color: #179067;
  transform: rotate(90deg);
  z-index: 10;
}
.color:nth-child(4):after {
  background-color: #476EAF;
  transform: rotate(120deg);
  z-index: 9;
}
.color:nth-child(5):after {
  background-color: #9f49ac;
  transform: rotate(150deg);
  z-index: 8;
}
.color:nth-child(6):after {
  background-color: #CC42A2;
  transform: rotate(180deg);
  z-index: 7;
}
.color:nth-child(7):after {
  background-color: #FF3BA7;
  transform: rotate(180deg);
}
.color:nth-child(8):after {
  background-color: #FF5800;
  transform: rotate(210deg);
}
.color:nth-child(9):after {
  background-color: #FF8100;
  transform: rotate(240deg);
}
.color:nth-child(10):after {
  background-color: #FEAC00;
  transform: rotate(270deg);
}
.color:nth-child(11):after {
  background-color: #FFCC00;
  transform: rotate(300deg);
}
.color:nth-child(12):after {
  background-color: #EDE604;
  transform: rotate(330deg);
}
<div class="wheel">
  <ul class="umbrella">
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
    <li class="color"></li>
  </ul>
</div>

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <filter id="blur">
    <feGaussianBlur stdDeviation="3" />
  </filter>
</svg>

Please note, in older versions of IE or old browsers, snippets won't work as they use HTML5 technology to run. I recommend testing in a local environment.

4

I'm afraid CSS doesn't allow for a linear-radial gradient. However, svg provides a solution, albeit crude. See the below topics for a solution.

How to draw a linear gradient circle by svg?

svg multiple color on circle stroke

1
  • nice but the solutions work only for a thin circle outline
    – Fanky
    Commented Jan 19, 2019 at 16:20
1

You can use 3 triangles cuted with common circle. Each triangle is transformed by central projection from long rectangle with linear gradient. I try it with SVG in Firefox, but Chromium does not support central projection in SVG but supports conical gradients, so see combined version for both browsers.

<svg version="2" viewBox="-207 -207 414 414" xmlns="http://www.w3.org/2000/svg">
 <defs>
  <radialGradient id="gWt">
   <stop style="stop-color:#fff" offset="0"/>
   <stop style="stop-color:#fff0" offset="1"/>
  </radialGradient>
  <!-- part for firefox: using central projection of 3 rectangles -->
  <linearGradient id="gYM" x1="0" x2="0" y1="0" y2="100%">
   <stop style="stop-color:#ef08" offset="0"/>
   <stop style="stop-color:#ff0" offset=".005"/>
   <stop style="stop-color:#fc0" offset=".1827"/>
   <stop style="stop-color:#f90" offset=".2924"/>
   <stop style="stop-color:#f60" offset=".3728"/>
   <stop style="stop-color:#f00" offset=".5"/>
   <stop style="stop-color:#f06" offset=".6272"/>
   <stop style="stop-color:#f09" offset=".7076"/>
   <stop style="stop-color:#f0c" offset=".8173"/>
   <stop style="stop-color:#f0f" offset=".995"/>
   <stop style="stop-color:#e0f8" offset="1"/>
  </linearGradient>
  <linearGradient id="gCY" href="#gYM">
   <stop style="stop-color:#0ef8" offset="0"/>
   <stop style="stop-color:#0ff" offset=".005"/>
   <stop style="stop-color:#0fc" offset=".1827"/>
   <stop style="stop-color:#0f9" offset=".2924"/>
   <stop style="stop-color:#0f6" offset=".3728"/>
   <stop style="stop-color:#0f0" offset=".5"/>
   <stop style="stop-color:#6f0" offset=".6272"/>
   <stop style="stop-color:#9f0" offset=".7076"/>
   <stop style="stop-color:#cf0" offset=".8173"/>
   <stop style="stop-color:#ff0" offset=".995"/>
   <stop style="stop-color:#fe08" offset="1"/>
  </linearGradient>
  <linearGradient id="gMC" href="#gYM">
   <stop style="stop-color:#f0e8" offset="0"/>
   <stop style="stop-color:#f0f" offset=".005"/>
   <stop style="stop-color:#c0f" offset=".1827"/>
   <stop style="stop-color:#90f" offset=".2924"/>
   <stop style="stop-color:#60f" offset=".3728"/>
   <stop style="stop-color:#00f" offset=".5"/>
   <stop style="stop-color:#06f" offset=".6272"/>
   <stop style="stop-color:#09f" offset=".7076"/>
   <stop style="stop-color:#0cf" offset=".8173"/>
   <stop style="stop-color:#0ff" offset=".995"/>
   <stop style="stop-color:#0fe8" offset="1"/>
  </linearGradient>
  <rect id="r" width="2000" height="700" style="transform:matrix3d(
      -29,0,0,100,
      0,1,0,0,
      0,0,1,0,
      200,-350,1,1
    ); mix-blend-mode:lighten"/>
 </defs>
 <clipPath id="cc">
  <circle r="200" id="c"/>
 </clipPath>
 <circle r="199" fill="#000"/>
 <g clip-path="url(#cc)" id="m">
  <use href="#r" fill="url(#gCY)" transform="rotate(-120)"/>
  <use href="#r" fill="url(#gYM)"/>
  <use href="#r" fill="url(#gMC)" transform="rotate(120)"/>
  <!-- for Chrome use conic gradient (does not work with any svg object but with foreign)
   Firefox ignores this object due to unknown keyword in style -->
 <foreignObject width="400" height="400" x="-200" y="-200" style="background:conic-gradient(from 90deg,
   #f00,#f0f,#00f,#0ff,#0f0,#ff0,#f00);
  background-repeat: no-repeat;
  background-position: center center;
  background-size: auto;"/>
 </g>
 <g>
  <!-- Points for visual test -->
  <circle cx="-200" r="6" fill="#0ff"/>
  <circle cx="-195.6" cy="-41.6" r="6" fill="#0fc"/>
  <circle cx="-182.7" cy="-81.3" r="6" fill="#0f9"/>
  <circle cx="-161.8" cy="-117.6" r="6" fill="#0f6"/>
  <circle cx="-133.8" cy="-148.6" r="6" fill="#0f3"/>
  <circle cx="-100" cy="-173.2" r="6" fill="#0f0"/>
  <circle cx="-61.8" cy="-190.2" r="6" fill="#3f0"/>
  <circle cx="-20.9" cy="-198.9" r="6" fill="#6f0"/>
  <circle cx="20.9" cy="-198.9" r="6" fill="#9f0"/>
  <circle cx="61.8" cy="-190.2" r="6" fill="#cf0"/>
  <circle cx="100" cy="-173.2" r="6" fill="#ff0"/>
  <circle cx="133.8" cy="-148.6" r="6" fill="#fc0"/>
  <circle cx="161.8" cy="-117.6" r="6" fill="#f90"/>
  <circle cx="182.7" cy="-81.3" r="6" fill="#f60"/>
  <circle cx="195.6" cy="-41.6" r="6" fill="#f30"/>
  <circle cx="200" r="6" fill="#f00"/>
  <circle cx="-195.6" cy="41.6" r="6" fill="#0cf"/>
  <circle cx="-182.7" cy="81.3" r="6" fill="#09f"/>
  <circle cx="-161.8" cy="117.6" r="6" fill="#06f"/>
  <circle cx="-133.8" cy="148.6" r="6" fill="#03f"/>
  <circle cx="-100" cy="173.2" r="6" fill="#00f"/>
  <circle cx="-61.8" cy="190.2" r="6" fill="#30f"/>
  <circle cx="-20.9" cy="198.9" r="6" fill="#60f"/>
  <circle cx="20.9" cy="198.9" r="6" fill="#90f"/>
  <circle cx="61.8" cy="190.2" r="6" fill="#c0f"/>
  <circle cx="100" cy="173.2" r="6" fill="#f0f"/>
  <circle cx="133.8" cy="148.6" r="6" fill="#f0c"/>
  <circle cx="161.8" cy="117.6" r="6" fill="#f09"/>
  <circle cx="182.7" cy="81.3" r="6" fill="#f06"/>
  <circle cx="195.6" cy="41.6" r="6" fill="#f03"/>
 </g>
 <circle r="200" fill="url(#gWt)"/>
</svg>

Offset values is calculated using the formula (for rectangular triangle 350x200):

0.5 ± tan(v/255.*pi/3)/350*100.

Where v is the value of the changing color channel.

HTML version (view the snippet in full window on Chrome)

*{
    margin:0;
    padding:0;
}
.c{
   height:90vmin;
   width:90vmin;
   margin:5vmin;
   overflow: hidden;
   border-radius:50%;
   position:absolute;
}
.c>div{
   position:relative;
   height:180vmin;
   width:100vmin;
   perspective: 0.40vmin;
   top:-45vmin;
   left:-4.8vmin;
}
.c>div>div{
   height: 100%;
   width: 100%;
   left:0;
   top:1%;
   height: 98%;
   transform-origin:99.98% 50%;
   position:relative;
   transform: rotate3d(0, 1, 0, -80deg);
   border:black;
}
#YM>div{
   background:linear-gradient(#ef08,#ff0 0.5%,#fc0 18.27%,#f90 29.24%,#f60 37.28%,#f00 50%,#f06 62.72%,#f09 70.76%,#f0c 81.73%,#f0f 99.5%,#e0f8);
}
#MC{
   transform: rotateZ(120deg);
}
#CY{
   transform: rotateZ(-120deg);
}
#MC>div{
   background:linear-gradient(#f0e8,#f0f 0.5%,#c0f 18.27%,#90f 29.24%,#60f 37.28%,#00f 50%,#06f 62.72%,#09f 70.76%,#0cf 81.73%,#0ff 99.5%,#0fe8);
}
#CY>div{
   background:linear-gradient(#0ef8,#0ff 0.5%,#0fc 18.27%,#0f9 29.24%,#0f6 37.28%,#0f0 50%,#6f0 62.72%,#9f0 70.76%,#cf0 81.73%,#ff0 99.5%,#fe08);
}
<div class="c"><div id="YM"><div></div></div></div>
<div class="c"><div id="MC"><div></div></div></div>
<div class="c"><div id="CY"><div></div></div></div>

0

SVG made my work very hard. The best solution I found is to use multiple circle slices and color them. And it is pure css3.

The question is: How to make the color changes smooth? I found the answer: By using blur filters.

Here is the complete solution: Conical Gradients in CSS

3
  • I just found out that in IE9+ blur filter does not exist outside canvas and svg. So this method could not be used in IE9+. what a surprise!!! Commented Jul 15, 2015 at 9:25
  • That is the reason why I recommended SVG/Canvas but upon seeing your answer I thought you didn't need to support IE9. Have a look at the answer I linked in comment or the polyfill mentioned in Ilya's answer. The polyfill also uses Canvas and/or SVG only.
    – Harry
    Commented Jul 15, 2015 at 9:26
  • Link-only answers are not very useful -- when the link dies or the content changes, the answer loses its value. Please update the answer to include useful content from your link, or this answer risks getting deleted.
    – TylerH
    Commented Oct 17, 2019 at 15:55
0

I was just playing with an idea for this for my own project. I didn't wanna use 'conic-gradient' as the support is very low for it at this time (mid 2019). so I came up with the following:

  background: 
    radial-gradient(circle at 38% 7% ,rgba(255,255,000,1) 20%,rgba(255,255,000,.0) 38%),
    radial-gradient(circle at 50% 0%,rgba(128,255,000,1) 22%,rgba(128,255,000,.0) 48%),
    radial-gradient(circle at 75% 7% ,rgba(000,255,000,1) 22%,rgba(000,255,000,.0) 48%),
    radial-gradient(circle at 93% 24%  ,rgba(000,255,128,1) 22%,rgba(000,255,128,.0) 48%),
    radial-gradient(circle at 100% 50%,rgba(000,255,255,1) 22%,rgba(000,255,255,.0) 48%),
    radial-gradient(circle at 93% 75% ,rgba(000,128,255,1) 22%,rgba(000,128,255,.0) 48%),
    radial-gradient(circle at 75% 93%,rgba(000,000,255,1) 22%,rgba(000,000,255,.0) 48%),
    radial-gradient(circle at 50% 100% ,rgba(128,000,255,1) 22%,rgba(128,000,255,.0) 48%),
    radial-gradient(circle at 25% 93%,rgba(255,000,255,1) 22%,rgba(255,000,255,.0) 48%),
    radial-gradient(circle at 7% 75%,rgba(255,000,128,1) 22%,rgba(255,000,128,.0) 48%),
    radial-gradient(circle at 0% 50%,rgba(255,000,000,1) 22%,rgba(255,000,000,.0) 48%),
    radial-gradient(circle at 7% 25%,rgba(255,128,000,1) 22%,rgba(255,128,000,.0) 48%);

https://jsfiddle.net/p5vxek3u/

Its not exact, but its close enough for my needs. I'm using it behind something with alpha transparency so you only get to see a small part at a time.

I thought I'd leave it here in case anyone needed it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.