I'm interested in creating a loading spinner entirely in CSS but in order to do so I would need to be able to draw a open ring shape like this:
The ring would draw itself around the circumference of the circle. Is this achievable in CSS?
You could use border-top-left-radius and border-top-right-radius properties to round the corners on the box according to the box's height (and added borders). Then add a border to top/right/left sides of the box to achieve the effect.
Creating an empty circle with CSS To create an empty circle first of all add an empty <div> element. Use CSS border-radius: 50% to make the div element circular. Additionally set the height, width and border of <div> element.
To create a circle that gradually draws it's outer path, use SVG.
SVG's stroke-dasharray
property will turn any path into a dashed line, which you can use to your advantage by setting the dash size to be almost as long as the path itself.
Then use a CSS animation to gradually change the stroke-dashoffset
to move the dash around the perimeter of your circle.
circle { fill: white; stroke: black; stroke-width: 2; stroke-dasharray: 250; stroke-dashoffset: 1000; animation: rotate 5s linear infinite; } @keyframes rotate { to { stroke-dashoffset: 0; } }
<svg height="100" width="100"> <circle cx="50" cy="50" r="40" /> </svg>
A simplified example that just relies on a single HTML element and CSS class might look like this :
.arc { /* Border size and color */ border: 2px solid #000; /* Creates a circle */ border-radius: 50%; /* Circle size */ height: 100px; width: 100px; /* Use transparent borders to define opening (more transparent = larger opening) */ border-top-color: transparent; border-left-color: transparent; /* Use transform to rotate to adjust where opening appears */ transform: rotate(300deg) }
Example
.arc { border: 2px solid #000; border-radius: 50%; height: 100px; width: 100px; border-top-color: transparent; transform: rotate(300deg) }
<div class='arc'></div>
You can apply a basic rotation to the previous static example by taking advantage of CSS-based animations using @keyframes
:
.arc { /* Border size and color */ border: 2px solid #000; /* Creates a circle */ border-radius: 50%; /* Circle size */ height: 100px; width: 100px; /* Use transparent borders to define opening (more transparent = larger opening) */ border-top-color: transparent; /* Rotate indefinitely (longer time = slower rotation) */ animation: rotate 2s infinite linear; } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
Example
.arc { border: 2px solid #000; border-radius: 50%; height: 100px; width: 100px; border-top-color: transparent; animation: rotate 2s infinite linear; } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
<div class='arc'></div>
Another approach that I came across, while not nearly as elegant as the previous approaches does appear to achieve your desired effect. In involves the use of several animations as well as showing/hiding different sections of the circle as necessary.
The code snippet contains an example demonstrating it.
Example
#container { position: absolute; width: 100px; height: 100px; animation: colors 1s infinite; } #halfclip { width: 50%; height: 100%; right: 0px; position: absolute; overflow: hidden; transform-origin: left center; animation: cliprotate 4s steps(2) infinite; -webkit-animation: cliprotate 4s steps(2) infinite; } .halfcircle { box-sizing: border-box; height: 100%; right: 0px; position: absolute; border: solid 2px transparent; border-top-color: #000; border-left-color: #000; border-radius: 50%; } #clipped { width: 200%; animation: rotate 2s linear infinite; -webkit-animation: rotate 2s linear infinite; } #fixed { width: 100%; transform: rotate(135deg); animation: showfixed 4s steps(2) infinite; -webkit-animation: showfixed 4s linear infinite; } @-webkit-keyframes cliprotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes cliprotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @-webkit-keyframes rotate { 0% { transform: rotate(-45deg); } 100% { transform: rotate(135deg); } } @keyframes rotate { 0% { transform: rotate(-45deg); } 100% { transform: rotate(135deg); } } @-webkit-keyframes showfixed { 0% { opacity: 0; } 49.9% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 1; } }
<div id="container"> <div id="halfclip"> <div class="halfcircle" id="clipped"> </div> </div> <div class="halfcircle" id="fixed"> </div> </div>
Taking advantage of SVG is probably the best way to address this problem, as it's explicitly designed to handle drawing within the browser. I'd highly recommend that approach if SVG support is available.
Dylan's response details what this implementation might look like.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With