How can I use circular or conical gradient using CSS?
Update: Chrome >68 now supports this!
This was actually being implemented as conic-gradient
.
This is using Chrome Canary (Nov 2017) with the Experimental Features Flag set to 'enabled', but this works in the regular version as well if you enable it.
Basic example:
div {
width: 100px;
height: 100px;
background: conic-gradient(#F00, #0F0);
}
<div></div>
Note that above example doesn't work on most browsers, but in mine, and hopefully, the future, it will display this:
Now if we build our own small loading widget
.wrapper {
background-color: #EEE;
width: 100px;
height: 100px;
padding: 50px;
}
.bg {
position: relative;
background: conic-gradient(#f00, #0f0);
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 100%;
}
.radial-overlay {
background-color: #EEE;
position: absolute;
top: 10px;
left: 10px;
width: 80px;
height: 80px;
border-radius: 100%;
}
.left-half {
position: absolute;
width: 100px;
height: 100px;
background-color: #EEE;
clip-path: inset(0px 50px 50px 0px);
}
.right-half {
position: absolute;
width: 100px;
height: 100px;
background-color: #EEE;
clip-path: inset(50px 50px 0px 00px);
transform: rotate(30deg);
}
<div class="wrapper">
<div class="bg">
<div class="radial-overlay"></div>
<div class="right-half"></div>
<div class="left-half"></div>
</div>
</div>
Now I know most of you can't see it, but this is how it looks with the flags on:
Now to edit the level, just adjust the transform: rotate(deg)
property, you'll have to juggle arround with the left half to cover unwanted parts, but clipping path can be a great solution here.
Now of course this is all fantastic, but still very much not usable in the current browsers, Lea Verou has created a fantastic polyfill for this though, more information about that can be found here
I just made a fiddle using 2 linear gradients as background then masked them with a circular stroke and animated it with JQuery:
var circle = $('#myMask circle');
var total = 2*Math.PI*circle.attr('r');
circle.attr('stroke-dasharray',total);
circle.attr('stroke-dashoffset',total);
$('button').click(function() {
var p = $('#percentage').val() || 0;
p = Math.max(0,Math.min(100,p))/100;
$('#percentage-text').text(p*100+'%');
circle.animate({'stroke-dashoffset': total-total*p}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg viewBox="0 0 100 100" width="100" height="100">
<defs>
<linearGradient id="grad1" x1="0" y1="50%" x2="0" y2="100%">
<stop offset="0%" stop-color="blue" />
<stop offset="100%" stop-color="purple" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="red" />
<stop offset="100%" stop-color="purple" />
</linearGradient>
<mask id="myMask">
<circle cx="50" cy="50" r="45" stroke-width="10" stroke="white" fill="transparent" transform="rotate(-90,50,50)"/>
</mask>
</defs>
<circle cx="50" cy="50" r="45" stroke-width="10" stroke="grey" fill="transparent" stroke-opacity=".2" />
<rect x="49.5" y="0" width="52" height="100" fill="url(#grad1)" mask="url(#myMask)"/>
<rect x="0" y="0" width="49.5" height="100" fill="url(#grad2)" mask="url(#myMask)"/>
<text id="percentage-text" x="50" y="55" text-anchor="middle">0%</text>
</svg>
<input id="percentage" type="text">
<button>Click me!</button>