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