Is it possible to create a circle using only HTML5 / CSS3 which has a border that only goes part way around the circle? If not, what techniques can I use to accomplish this effect? I would prefer to use pure DOM elements, but if I have to I can draw on canvas or spin up an SVG.
This method requires no JS, no extra element and not even any pseudos, just a handful of CSS declarations. It also works if the element has a (semi)transparent background
in addition to this partial border
.
It uses a two layer mask
, one being a conic-gradient
which creates a visible pie selection and whose size is relative to the border-box
and the second being a simple full cover layer restricted to the padding-box
.
First, we make our element circular (arbitrary width
, an aspect-ratio
of 1
and a border-radius
set to 50%
) and give it a border
.
Then, we set a mask
that's a conic-gradient()
, relative to the border-box
, covering a percentage --p
of our element (by default starting from 12 o'clock and going clockwise).
On top of this mask
layer, we set a full cover one restricted to the padding-box
.
.circular-progress {
border: solid 1.5em hotpink;
width: 50vmin;
aspect-ratio: 1;
border-radius: 50%;
background: hsla(180, 100%, 50%, .5);
--mask:
linear-gradient(red, red) padding-box,
conic-gradient(red var(--p, 17%), transparent 0%) border-box;
-webkit-mask: var(--mask);
mask: var(--mask)
}
/* just to make it obvious it works with semitrasparent background */
body {
background:
url(https://images.unsplash.com/photo-1693483923875-cdd9ef4a8046?w=800)
50%/ cover
}
<div class='circular-progress'></div>
If we want to animate this, we need to also register --p
.
@property --p {
syntax: '<percentage>';
initial-value: 0%;
inherits: true
}
.circular-progress {
border: solid 1.5em hotpink;
width: 50vmin;
aspect-ratio: 1;
border-radius: 50%;
background: hsla(180, 100%, 50%, .5);
--mask:
linear-gradient(red, red) padding-box,
conic-gradient(red var(--p), transparent 0%) border-box;
-webkit-mask: var(--mask);
mask: var(--mask);
animation: p 4s linear infinite
}
@keyframes p { to { --p: 100% } }
/* just to make it obvious it works with semitrasparent background */
body {
background:
url(https://images.unsplash.com/photo-1693483923875-cdd9ef4a8046?w=800)
50%/ cover
}
<div class='circular-progress'></div>
Registering custom properties this way in order to animate them is supported in Chromium browsers and in Safari and it's coming soonish in Firefox Nightly too.
Yes, it is possible - see this:
.circle {
position: relative;
margin: 7em auto;
width: 16em;
height: 16em;
border-radius: 50%;
background: lightblue;
}
.arc {
overflow: hidden;
position: absolute;
/* make sure top & left values are - the width of the border */
/* the bottom right corner is the centre of the parent circle */
top: -1em;
right: 50%;
bottom: 50%;
left: -1em;
/* the transform origin is the bottom right corner */
transform-origin: 100% 100%;
/* rotate by any angle */
/* the skew angle is 90deg - the angle you want for the arc */
transform: rotate(45deg) skewX(30deg);
}
.arc:before {
box-sizing: border-box;
display: block;
border: solid 1em navy;
width: 200%;
height: 200%;
border-radius: 50%;
transform: skewX(-30deg);
content: '';
}
<div class='circle'>
<div class='arc'></div>
</div>