I want to create a rainbow around the circumference, as in the image below.

enter image description here

But how do I draw a curved and multi-colored gradient?

Here is my current code:

<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="test"> <stop offset="0%" stop-color="#f00"/> <stop offset="100%" stop-color="#0ff"/> </linearGradient> </defs> <circle cx="50" cy="50" r="40" fill="none" stroke="url(#test)" stroke-width="6"/> </svg> 

Translation question: svg multiple color on circle stroke

  • one
    Other answers are accepted that demonstrate a different technique for the answer. For example: another version of JS, solutions with CSS, etc. At least 10 answers to one question, as is the case with enSO, - no one will be left behind. - Alexandr_TT
  • one
    I also thought about it ... there is still D3JS in essence, this is the same thing, nothing new, but more elegantly - Akubik

3 answers 3

This is possible with the help of the conic-gradient polyfill by Leah Vera.

 .circle { background: conic-gradient(#f00, #ff00bd, #0020ff, #00f3ff, #00ff08, #fff700, #f00); border-radius: 50%; width: 200px; height: 200px; position: relative; } .circle:after { position: absolute; content: ""; left: 20px; top: 20px; width: calc(100% - 40px); height: calc(100% - 40px); background: #fff; border-radius: 50%; } 
 <div class="circle"></div> <script src="https://leaverou.imtqy.com/prefixfree/prefixfree.min.js"></script> <script src="https://leaverou.imtqy.com/conic-gradient/conic-gradient.js"></script> 

  • Take png, turn it into base64, put it into svg and turn it into base64 again. Strange scheme ... And also the accuracy of the center raises some doubts. - Qwertiy ♦
  • @Qwertiy is even more - take a canvas, draw a picture on it, turn it into a png and then everything else. Apparently, on the canvas, a conical gradient of lines is still faster to draw than to do a bunch of lines at once. - Sasha Omelchenko
  • @SashaOmelchenko, I meant that the png on base64 should already seem to be placed in the background. It is not clear why we need intermediate svg. - Qwertiy ♦
  • @Qwertiy why, by default, Leah made such a conclusion to me and I myself was not clear. but suddenly it will be needed - this script can be used not only as a polyfill, it has an API, which can return png / base64 right away. - Sasha Omelchenko

This approach will not work. SVG has no conical gradients. To imitate the effect, you would need to fake it with a large number of small segments. Or apply some other similar technique.

Update:

Here is an example. I approximate 360deg shades on six stretches created by path's . Each path contains an arc that covers 60 degrees of a circle. I use a linear gradient to interpolate the color from the beginning to the end of each path.

It’s not perfect (you can see some breaks where colors occur), but most people will not notice. You can increase accuracy using more than six segments.

  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="220" height="220" viewBox="-10 -10 220 220"> <defs> <linearGradient id="redyel" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#ff0000"/> <stop offset="100%" stop-color="#ffff00"/> </linearGradient> <linearGradient id="yelgre" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#ffff00"/> <stop offset="100%" stop-color="#00ff00"/> </linearGradient> <linearGradient id="grecya" gradientUnits="objectBoundingBox" x1="1" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#00ff00"/> <stop offset="100%" stop-color="#00ffff"/> </linearGradient> <linearGradient id="cyablu" gradientUnits="objectBoundingBox" x1="1" y1="1" x2="0" y2="0"> <stop offset="0%" stop-color="#00ffff"/> <stop offset="100%" stop-color="#0000ff"/> </linearGradient> <linearGradient id="blumag" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="0" y2="0"> <stop offset="0%" stop-color="#0000ff"/> <stop offset="100%" stop-color="#ff00ff"/> </linearGradient> <linearGradient id="magred" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="1" y2="0"> <stop offset="0%" stop-color="#ff00ff"/> <stop offset="100%" stop-color="#ff0000"/> </linearGradient> </defs> <g fill="none" stroke-width="15" transform="translate(100,100)"> <path d="M 0,-100 A 100,100 0 0,1 86.6,-50" stroke="url(#redyel)"/> <path d="M 86.6,-50 A 100,100 0 0,1 86.6,50" stroke="url(#yelgre)"/> <path d="M 86.6,50 A 100,100 0 0,1 0,100" stroke="url(#grecya)"/> <path d="M 0,100 A 100,100 0 0,1 -86.6,50" stroke="url(#cyablu)"/> <path d="M -86.6,50 A 100,100 0 0,1 -86.6,-50" stroke="url(#blumag)"/> <path d="M -86.6,-50 A 100,100 0 0,1 0,-100" stroke="url(#magred)"/> </g> </svg> 

Fiddle example

Update 2:

For options with six or more segments, there is a javascript solution that will create a circle with any number of segments.

 function makeColourWheel(numSegments) { if (numSegments <= 0) numSegments = 12; if (numSegments > 360) numSegments = 360; var svgns = xmlns="http://www.w3.org/2000/svg"; var svg = document.getElementById("colourwheel"); var defs = svg.getElementById("defs"); var paths = svg.getElementById("paths"); var radius = 100; var stepAngle = 2 * Math.PI / numSegments; var lastX = 0; var lastY = -radius; var lastAngle = 0; for (var i=1; i<=numSegments; i++) { var angle = i * stepAngle; // Calculate this arc end point var x = radius * Math.sin(angle); var y = -radius * Math.cos(angle); // Create a path element var arc = document.createElementNS(svgns, "path"); arc.setAttribute("d", "M " + lastX.toFixed(3) + "," + lastY.toFixed(3) + " A 100,100 0 0,1 " + x.toFixed(3) + "," + y.toFixed(3)); arc.setAttribute("stroke", "url(#wheelseg" + i + ")"); // Append it to our SVG paths.appendChild(arc); // Create a gradient for this segment var grad = document.createElementNS(svgns, "linearGradient"); grad.setAttribute("id", "wheelseg"+i); grad.setAttribute("gradientUnits", "userSpaceOnUse"); grad.setAttribute("x1", lastX.toFixed(3)); grad.setAttribute("y1", lastY.toFixed(3)); grad.setAttribute("x2", x.toFixed(3)); grad.setAttribute("y2", y.toFixed(3)); // Make the 0% stop for this gradient var stop = document.createElementNS(svgns, "stop"); stop.setAttribute("offset", "0%"); hue = Math.round(lastAngle * 360 / Math.PI / 2); stop.setAttribute("stop-color", "hsl(" + hue + ",100%,50%)"); grad.appendChild(stop); // Make the 100% stop for this gradient stop = document.createElementNS(svgns, "stop"); stop.setAttribute("offset", "100%"); hue = Math.round(angle * 360 / Math.PI / 2); stop.setAttribute("stop-color", "hsl(" + hue + ",100%,50%)"); grad.appendChild(stop); // Add the gradient to the SVG defs.appendChild(grad); // Update lastx/y lastX = x; lastY = y; lastAngle = angle; } } makeColourWheel(60); 
 <svg id="colourwheel" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="-10 -10 220 220"> <defs id="defs"> </defs> <g id="paths" fill="none" stroke-width="15" transform="translate(100,100)"> </g> </svg> 

Translation of the answer: svg multiple color on @Laaau stroke

    Perhaps I will leave it here ... On the Internet, the question is still relevant.

    SVG:

    + Scalability;
    + Ability to animate;
    + Small volume and clear code.

    Canvas:

    + Scalability;
    + Ability to animate;
    - The amount of code is more, calculations are more complicated.

    CSS:

    + Native code, without the involvement of new technologies;
    - Scalability and animation is difficult;
    - Opacity of the inside of the circle.

     /************* * SVG * ************/ var oView = document.getElementById('svg'), nHue = 360, oCircle, nAngle; while (nHue--) { nAngle = nHue * Math.PI / 180; oCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); oCircle.setAttribute('cx', 50 - Math.sin(nAngle) * 45); oCircle.setAttribute('cy', 50 - Math.cos(nAngle) * 45); oCircle.setAttribute('r', '5'); oCircle.setAttribute('fill', 'hsl(' + nHue + ', 100%, 50%)'); oView.appendChild(oCircle); } /************** * CANVAS * *************/ var cnv = document.getElementById('cnv'); var ctx = cnv.getContext('2d'); var nCY = cnv.height / 2; var nCX = cnv.width / 2; var nR = cnv.width / 2; var nHues = 360; while (nHues--) { nStartCX = nCX + (Math.cos(nHues * Math.PI / 180) * nR * 0.8); nStartCY = nCY + (Math.sin(nHues * Math.PI / 180) * nR * 0.8); nStopCX = nCX + (Math.cos((nHues + 2) * Math.PI / 180) * nR * 0.8); nStopCY = nCY + (Math.sin((nHues + 2) * Math.PI / 180) * nR * 0.8); nStartDX = nCX + (Math.cos(nHues * Math.PI / 180) * nR); nStartDY = nCY + (Math.sin(nHues * Math.PI / 180) * nR); nStopDX = nCX + (Math.cos((nHues + 2) * Math.PI / 180) * nR); nStopDY = nCY + (Math.sin((nHues + 2) * Math.PI / 180) * nR); ctx.save(); ctx.beginPath(); ctx.moveTo(nStartCX, nStartCY); ctx.lineTo(nStartDX, nStartDY); ctx.lineTo(nStopDX, nStopDY); ctx.lineTo(nStopCX, nStopCY); ctx.fillStyle = 'hsl(' + nHues + ', 100%, 50%)'; ctx.fill(); ctx.closePath(); } ctx.restore(); 
     /************* * CSS * *************/ .rgb { border-radius: 50%; position: relative; background: radial-gradient(ellipse at center, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 1) 56%, rgba(255, 255, 255, 0) 57%, rgba(255, 255, 255, 0) 100%), /* white hole */ linear-gradient(10deg, rgb(255, 0, 0) 0%, rgba(255, 0, 0, 0) 40%), /* red */ linear-gradient(70deg, rgb(255, 255, 0) 0%, rgba(255, 255, 0, 0) 50%), /* yeloow */ linear-gradient(130deg, rgb(0, 255, 0) 0%, rgba( 0, 255, 0, 0) 45%), /* gren */ linear-gradient(190deg, rgb(0, 255, 255) 0%, rgba(0, 255, 255, 0) 50%), /* cyan */ linear-gradient(250deg, rgb(0, 0, 255) 0%, rgba(0, 0, 255, 0) 50%), /* blue */ linear-gradient(310deg, rgb(255, 0, 255) 0%, rgba(255, 0, 255, 0) 50%)/* magenta */ ; } canvas, svg, div { display: inline-block; height: 180px; width: 180px; } pre { top: 55px; position: absolute; font: bold 26px monospace; text-shadow: 1px 3px 3px rgba(0, 0, 0, 0.75); } 
     <svg viewBox="0 0 100 100" id='svg'></svg> <canvas id="cnv" width="180" height="180"></canvas> <div class="rgb"></div> <pre> SVG Canvas CSS</pre>