I recently saw this style on a website and found that it was implemented in div+ CSS, usually with canvas, so I wrote a curved progress bar following this idea
Circular progress bar with CSS and HTML and var() function
The final result
Clip properties
W3cschool emphasizes that the object used for this attribute is an absolutely positioned elementLet’s start with this propertyClip attribute: Clip :rect(Top,right,bottom,left)
I want to show half of the bottom square if it’s all 1rem wide and 1rem highClip :rect(0,0.5rem,1rem,0rem)
<div style="position: relative; width: 1rem; height:1rem;">
<div style="position: absolute; width: 1rem; height:1rem; background: red; Clip: the rect (0,0.5 rem, rem, 1 0);"></div>
</div>
Copy the code
This corresponds to the four boundaries of the square from top=0 to bottom=1rem and left=0 to right=0.5rem
Start drawing a semicircle
Since one can cut half of a square and show the semicircle, that’s easy to do
.half_circle{ position: absolute; width: 1rem; height:1rem; Clip: the rect (0,0.5 rem, rem, 1 0); border-radius:50%; box-sizing:border-box; /* Border :0.08rem solid red} /* border:0.08rem solid red}<div style="position: relative; width: 1rem; height:1rem;">
<div class="half_circle"></div>
</div>
Copy the code
And then I rotate the semicircle
When the progress bar is less than 50%, the arc of the whole progress bar shall not exceed the range of the whole semicircle
.half_circle{ position: absolute; width: 1rem; height:1rem; Clip: the rect (0,0.5 rem, rem, 1 0); border-radius:50%; box-sizing:border-box; /* Border :0.08rem solid red; /* Border :0.08rem solid red; transform: rotate(50deg) }<div style="position: relative; width: 1rem; height:1rem;">
<div class="half_circle"></div>
</div>
Copy the code
Progress bar below 50%
. Half_circle_box {clip: the rect (0, 1 rem, 1 rem, 0.5 rem); position: absolute; width: 1rem; height:1rem; } .half_circle{ position: absolute; width: 1rem; height:1rem; Clip: the rect (0,0.5 rem, rem, 1 0); border-radius:50%; box-sizing:border-box; /* Border :0.08rem solid red; /* Border :0.08rem solid red; transform: rotate(50deg) }<div style="position: relative; width: 1rem; height:1rem;">
<div class="half_circle_box">
<div class="half_circle"></div>
</div>
</div>
Copy the code
Complete more than 50% of the progress arc
Now the progress bar below 50% is complete, and then the progress bar above 50% obviously one semicircle cannot be completed and then I have to show another semicircle. When I want to show a 240deg arc, I can see that the two semicircles one rotates 180deg and one selects 60deg which is 240deg
. Half_circle_box {/ * clip: the rect (0, 1 rem, 1 rem, 0.5 rem); */ position: absolute; width: 1rem; height:1rem; } .half_circle{ position: absolute; width: 1rem; height:1rem; Clip: the rect (0,0.5 rem, rem, 1 0); border-radius:50%; box-sizing:border-box; /* Border :0.08rem solid red; /* Border :0.08rem solid red; transform: rotate(180deg) } .other_half_circle{ position: absolute; width: 1rem; height:1rem; Clip: the rect (0, 1 rem, 1 rem, 0.5 rem); border-radius:50%; box-sizing:border-box; Border: 0.08 rem solid red; transform: rotate(60deg) }<div style="position: relative; width: 1rem; height:1rem;">
<div class="half_circle_box">
<div class="half_circle"></div>
<div class="other_half_circle"></div>
</div>
</div>
Copy the code
The general correlation comes out
Here is a complete code example
The complete code
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<style>
html {
font-size: 160px;
}
.circle {
position: relative;
/* font-size: 193px; * /
width: 1rem;
height: 1rem;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
border-radius: 50%;
background-color: #e7ebe3;
}
.circle:after {
position: absolute;
top: 0.08 rem;
left: 0.08 rem;
display: block;
content: "";
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
border-radius: 50%;
background-color: white;
width: 0.84 rem;
height: 0.84 rem;
-webkit-transition-property: all;
-moz-transition-property: all;
-o-transition-property: all;
transition-property: all;
-webkit-transition-duration: 0.2 s;
-moz-transition-duration: 0.2 s;
-o-transition-duration: 0.2 s;
transition-duration: 0.2 s;
-webkit-transition-timing-function: ease-in;
-moz-transition-timing-function: ease-in;
-o-transition-timing-function: ease-in;
transition-timing-function: ease-in;
}
.circle .slice {
position: absolute;
width: 1rem;
height: 1rem;
}
.bar {
width: 1rem;
height: 1rem;
position: absolute;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
border-radius: 50%;
border: 0.08 rem solid #307bbb;
box-sizing: border-box;
clip: rect(0.0.5 rem.1rem.0rem);
/* Cut a semicircle */
transform: rotate(calc(1deg * var(--deg)));
}
.fill {
width: 1rem;
height: 1rem;
position: absolute;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
border-radius: 50%;
border: 0.08 rem solid #307bbb;
box-sizing: border-box;
clip: rect(0.1rem.1rem.0.5 rem);
/* Cut a semicircle */
transform: rotate(calc(1deg * var(--deg)));
}
</style>
<body>
<div v-cloak id="app">
<div class="circle">
<div
style="position: absolute; z-index: 999; width: 1rem; height:1rem; display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: 20px;">
<div>
{{circleDeg}}deg
</div>
<div>
{{(circleDeg / 360) | toFixed2}}%
</div>
</div>
<div :style="circleDeg > 180 ? Clip: rect(0, 1rem, 1rem, 0.5rem); '" class="slice">
<div :style="{'--deg':circleDeg > 180 ? 180 : circleDeg}" class="bar"></div>
<div v-if="circleDeg > 180" :style="{'--deg':circleDeg - 180}" class="fill"></div>
</div>
</div>
<! -- <span>22%</span> -->Angle:<input v-model="deg" type="number" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: "#app".data: function () {
return {
deg: 45}},filters: {toFixed2:function(num){
return (num * 100).toFixed(2)}},computed: {
circleDeg: function () {
// May have a negative degree
return Math.abs(this.deg) % 360}}})</script>
</body>
</html>
Copy the code