JSFiddle - React, Tailwind, and code Playground
HTML
<h3>Думаю для портфолио будет норм</h3>
<button id="btn">Сюда вешаем любое событие</button>
<ul class="wrap">
<li class="item">
<h3>HTML+CSS</h3>
<svg class="circles" viewBox="0 0 110 110">
<circle r="45" cx="50%" cy="50%" fill="none" class="circle_first"></circle>
<circle r="45" cx="50%" cy="50%" transform="rotate(-90 55 55)" class="circle__second circle-75"></circle>
</svg>
<span class="num">0%</span>
</li>
<li class="item">
<h3>JS</h3>
<svg class="circles" viewBox="0 0 110 110">
<circle r="45" cx="50%" cy="50%" fill="none" class="circle_first"></circle>
<circle r="45" cx="50%" cy="50%" transform="rotate(-90 55 55)" class="circle__second circle-47"></circle>
</svg>
<span class="num">0%</span>
</li>
<li class="item">
<h3>PHP</h3>
<svg class="circles" viewBox="0 0 110 110">
<circle r="45" cx="50%" cy="50%" fill="none" class="circle_first"></circle>
<circle r="45" cx="50%" cy="50%" transform="rotate(-90 55 55)" class="circle__second circle-54"></circle>
</svg>
<span class="num">0%</span>
</li>
</ul>
CSS
#btn,footer{display:block}footer{margin:100% auto 0;text-align:center;width:100%}body{background:rgba(130,130,200,.5)}#btn{width:300px;height:50px;background:#935;color:#fff;border:0;border-radius:100px;margin:3rem auto 0;font-size:1rem}#btn:hover{background:#333}#btn:active,#btn:focus{outline:0}#res{font-size:1rem;margin-top:2rem;-webkit-transform:rotate(15deg);transform:rotate(15deg)}.circles{fill:none;stroke-width:15}.circle_first{stroke:#dfdcd5}.circle__second{stroke:#1bb696;stroke-dasharray:.001 282.6}.item{display:inline-block;border:1px solid #ccc;width:120px;height:180px;position:relative;z-index:3}.num{position:absolute;top:calc(66% - 8px);left:calc(50% - 15px);font-family:sans-serif;color:#fff;z-index:1}.wrap{width:90%;margin:2rem auto}#res,h3{color:#fff;font-family:sans-serif;text-align:center}
JavaScript
var start = document.getElementById('btn');
start.addEventListener("click", startAnimate);
function startAnimate () {
var circles = document.querySelectorAll('.circles');
var item = document.querySelectorAll('.item');
var numArr = [];
function takePercentage(str) {
// Либо так:
//console.log(str.slice(-2));
//return str.slice(-2);
//Либо так:
let s = str.split("circle-")
//console.log(s[1]);
return s[1];
}
function runNum(el, stopNum, speed) {
let timerId = setInterval(function(){
let s = el.lastElementChild.textContent;
s = s.substring(0, s.length - 1);
s++;
el.lastElementChild.innerHTML = s + "%";
if(el.lastElementChild.textContent == stopNum + "%"){
clearInterval(timerId);
}
}, speed);
}
for(let i = 0; i < circles.length; i++) {
numArr.push(takePercentage(circles[i].lastElementChild.getAttribute('class')));
}
runNum(item[0], numArr[0], 50);
runNum(item[1], numArr[1], 100);
runNum(item[2], numArr[2], 150);
/*Анимация кругов*/
var oneCircle = document.querySelector(".circles .circle-75");
var twoCircle = document.querySelector(".circles .circle-47");
var threeCircle = document.querySelector(".circles .circle-54");
aggregate(oneCircle, 217, 18);
aggregate(twoCircle, 132, 30);
aggregate(threeCircle, 157, 50);
function aggregate(el, stopNum, speed) {
let timerId = setInterval(function(){
let styleArr = getComputedStyle(el);
let firstVal = styleArr.strokeDasharray.split(" ");
firstVal[0] = firstVal[0].substring(0, firstVal[0].length - 3);
el.style.strokeDasharray = Math.floor(firstVal[0]) + 1 + ", 282.6";
if(el.style.strokeDasharray == stopNum + ", 282.6"){
clearInterval(timerId);
}
}, speed);
}
}