<div class="block">
    <h1 class="title">Lorem ipsum dolor, sit amet consectetur adipisicing elit.</h1>
    <div class="wrapper">
        <p class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Molestiae nulla illo, dolor repudiandae blanditiis ipsa esse? Corrupti quam dolore doloremque tempore quis excepturi dolorem culpa, praesentium labore deserunt ut itaque!</p>
        <div class="progress" data-progress="54" data-color="#28792F">
            <svg class="svg-icon" viewBox="0 0 20 20">
                <path d="M14.999,8.543c0,0.229-0.188,0.417-0.416,0.417H5.417C5.187,8.959,5,8.772,5,8.543s0.188-0.417,0.417-0.417h9.167C14.812,8.126,14.999,8.314,14.999,8.543 M12.037,10.213H5.417C5.187,10.213,5,10.4,5,10.63c0,0.229,0.188,0.416,0.417,0.416h6.621c0.229,0,0.416-0.188,0.416-0.416C12.453,10.4,12.266,10.213,12.037,10.213 M14.583,6.046H5.417C5.187,6.046,5,6.233,5,6.463c0,0.229,0.188,0.417,0.417,0.417h9.167c0.229,0,0.416-0.188,0.416-0.417C14.999,6.233,14.812,6.046,14.583,6.046 M17.916,3.542v10c0,0.229-0.188,0.417-0.417,0.417H9.373l-2.829,2.796c-0.117,0.116-0.71,0.297-0.71-0.296v-2.5H2.5c-0.229,0-0.417-0.188-0.417-0.417v-10c0-0.229,0.188-0.417,0.417-0.417h15C17.729,3.126,17.916,3.313,17.916,3.542 M17.083,3.959H2.917v9.167H6.25c0.229,0,0.417,0.187,0.417,0.416v1.919l2.242-2.215c0.079-0.077,0.184-0.12,0.294-0.12h7.881V3.959z"></path>
            </svg>
            54%
        </div>
    </div>
</div>
<div class="block">
    <h1 class="title">Ab libero magni, provident sed doloremque sapiente quam.</h1>
    <div class="wrapper">
        <p class="text">Blanditiis similique harum enim dignissimos nobis voluptate magnam saepe dolorum quibusdam dolores doloremque iusto quam aliquam facilis ipsa vero delectus, earum accusantium itaque perferendis repudiandae quae deserunt eligendi. Assumenda, magnam.</p>
        <div class="progress" data-progress="12" data-color="#B460CA">
            <svg class="svg-icon" viewBox="0 0 20 20">
                <path d="M8.627,7.885C8.499,8.388,7.873,8.101,8.13,8.177L4.12,7.143c-0.218-0.057-0.351-0.28-0.293-0.498c0.057-0.218,0.279-0.351,0.497-0.294l4.011,1.037C8.552,7.444,8.685,7.667,8.627,7.885 M8.334,10.123L4.323,9.086C4.105,9.031,3.883,9.162,3.826,9.38C3.769,9.598,3.901,9.82,4.12,9.877l4.01,1.037c-0.262-0.062,0.373,0.192,0.497-0.294C8.685,10.401,8.552,10.18,8.334,10.123 M7.131,12.507L4.323,11.78c-0.218-0.057-0.44,0.076-0.497,0.295c-0.057,0.218,0.075,0.439,0.293,0.495l2.809,0.726c-0.265-0.062,0.37,0.193,0.495-0.293C7.48,12.784,7.35,12.562,7.131,12.507M18.159,3.677v10.701c0,0.186-0.126,0.348-0.306,0.393l-7.755,1.948c-0.07,0.016-0.134,0.016-0.204,0l-7.748-1.948c-0.179-0.045-0.306-0.207-0.306-0.393V3.677c0-0.267,0.249-0.461,0.509-0.396l7.646,1.921l7.654-1.921C17.91,3.216,18.159,3.41,18.159,3.677 M9.589,5.939L2.656,4.203v9.857l6.933,1.737V5.939z M17.344,4.203l-6.939,1.736v9.859l6.939-1.737V4.203z M16.168,6.645c-0.058-0.218-0.279-0.351-0.498-0.294l-4.011,1.037c-0.218,0.057-0.351,0.28-0.293,0.498c0.128,0.503,0.755,0.216,0.498,0.292l4.009-1.034C16.092,7.085,16.225,6.863,16.168,6.645 M16.168,9.38c-0.058-0.218-0.279-0.349-0.498-0.294l-4.011,1.036c-0.218,0.057-0.351,0.279-0.293,0.498c0.124,0.486,0.759,0.232,0.498,0.294l4.009-1.037C16.092,9.82,16.225,9.598,16.168,9.38 M14.963,12.385c-0.055-0.219-0.276-0.35-0.495-0.294l-2.809,0.726c-0.218,0.056-0.351,0.279-0.293,0.496c0.127,0.506,0.755,0.218,0.498,0.293l2.807-0.723C14.89,12.825,15.021,12.603,14.963,12.385"></path>
            </svg>
            12%
        </div>
    </div>
</div>
<div class="block">
        <h1 class="title">Voluptatibus blanditiis mollitia officia sapiente expedita est asperiores?</h1>
    <div class="wrapper">
        <p class="text">Tempore nam ad quas veniam? Ex, eveniet eaque dignissimos culpa quisquam consectetur, impedit nostrum soluta similique quaerat modi error, tempora officiis enim? Necessitatibus autem error veritatis? Dicta maxime aperiam sed?</p>
        <div class="progress" data-progress="87" data-color="#BB3E58">
            <svg class="svg-icon" viewBox="0 0 20 20">
                <path d="M17.308,7.564h-1.993c0-2.929-2.385-5.314-5.314-5.314S4.686,4.635,4.686,7.564H2.693c-0.244,0-0.443,0.2-0.443,0.443v9.3c0,0.243,0.199,0.442,0.443,0.442h14.615c0.243,0,0.442-0.199,0.442-0.442v-9.3C17.75,7.764,17.551,7.564,17.308,7.564 M10,3.136c2.442,0,4.43,1.986,4.43,4.428H5.571C5.571,5.122,7.558,3.136,10,3.136 M16.865,16.864H3.136V8.45h13.729V16.864z M10,10.664c-0.854,0-1.55,0.696-1.55,1.551c0,0.699,0.467,1.292,1.107,1.485v0.95c0,0.243,0.2,0.442,0.443,0.442s0.443-0.199,0.443-0.442V13.7c0.64-0.193,1.106-0.786,1.106-1.485C11.55,11.36,10.854,10.664,10,10.664 M10,12.878c-0.366,0-0.664-0.298-0.664-0.663c0-0.366,0.298-0.665,0.664-0.665c0.365,0,0.664,0.299,0.664,0.665C10.664,12.58,10.365,12.878,10,12.878"></path>
            </svg>
            87%
        </div>
    </div>
</div>
body {
    margin: 20px 0;
    padding: 0 120px;
    font: 20px/1.25 Cambria, 'Times New Roman', serif;
    background-color: #f5f5f5;
}

.block {
    &:nth-child(1) {
        color: #28792F;
    }
    
    &:nth-child(2) {
        color: #B460CA;
    }
    
    &:nth-child(3) {
        color: #BB3E58;
    }
    
    &:nth-child(1),
    &:nth-child(3) {
        .wrapper {
            grid-template-columns: max-content 1fr;

            .text {
                grid-column: 2;
            }

            .progress {
                grid-column: 1;
            }
        }
    }
    
    &:nth-child(2) {
        .wrapper {
            grid-template-columns: 1fr max-content;

            .text {
                grid-column: 1;
            }

            .progress {
                grid-column: 2;
            }
        }
    }
}

.title {
    margin: 20px 0;
    font-size: 2.25rem;
}

.text {
    margin: 0px;
}

.progress {
    position: relative;
    min-height: 150px;
    gap: 10px;
    display: grid;
    grid-auto-rows: max-content;
    justify-items: center;
    font-size: 2rem;
    
    .svg-icon {
        position: absolute;
        top: 75px;
        transform: translateY(-50%);
    }
}

.svg-icon {
    width: 60px;
    height: 60px;
    display: block;
    fill: currentColor;
}

.wrapper {
    gap: 20px;
    display: grid;
    
    .text,
    .progress {
        grid-row: 1;
    }
}
View Compiled
// Utils
const clamp = (min, max, value) => Math.max(min, Math.min(max, value));

const lerp = (min, max, value) => (1 - value) * min + value * max;

const easeInOutSine = x => -(Math.cos(Math.PI * x) - 1) / 2;

// Circle bar logic
const createCircleBar = (width, height, progress, color) => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    [canvas.width, canvas.height] = [width, height];
    
    const offset = -Math.PI / 2;
    const lineWidth = 5;
    const radius = Math.min(width / 2, height / 2);
    const duration = 600;
    let inProgress = false;
    let isDrawed = false;
    
    const reset = () => {
        context.clearRect(0, 0, width, height);
        isDrawed = false;
    };
    
    const draw = progress => {
        const angle = Math.PI / 50 * progress;
        context.clearRect(0, 0, width, height);
        context.lineWidth = lineWidth;
        context.lineCap = 'round';
        
        context.beginPath();
        context.arc(width / 2, height / 2, radius - lineWidth * 1.5, 0, Math.PI * 2);
        context.strokeStyle = '#ffffff';
        context.stroke();
        context.closePath();
        
        context.beginPath();
        context.arc(width / 2, height / 2, radius - lineWidth / 2, offset, angle + offset);
        context.strokeStyle = color;
        context.stroke();
        context.closePath();
    };
    
    const animate = () => {
        if (inProgress || isDrawed) {
            return;
        }
        
        const start = performance.now();
        inProgress = true;
        
        const step = () => {
            const diff = performance.now() - start;
            const current = clamp(0, progress, lerp(0, progress, easeInOutSine(diff / duration)));
            draw(current);
            
            if (diff <= duration) {
                requestAnimationFrame(step);
            } else {
                inProgress = false;
                isDrawed = true;
            }
        };
        
        requestAnimationFrame(step);
    };
    
    return {
        canvas,
        draw,
        animate,
        reset
    };
};

// Animation
const circleBars = new WeakMap();

const observer = new IntersectionObserver(entries => entries.forEach(entry => {
    if (entry.intersectionRatio === 0) {
        circleBars.get(entry.target)?.reset();
    } else if (entry.intersectionRatio >= 0.2) {
        circleBars.get(entry.target)?.animate();
    }
}), { threshold: [0, 0.2, 0.4, 0.6, 0.8, 1] });

document.querySelectorAll('.progress').forEach(element => {
    const { progress, color } = element.dataset;
    const circleBar = createCircleBar(150, 150, parseFloat(progress || '0'), color || '#000000');
    
    circleBars.set(circleBar.canvas, circleBar);
    observer.observe(circleBar.canvas);
    element.prepend(circleBar.canvas);
});


External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.