円形プログレスカウンター
概要
円形のメーターと進捗度合いを示すアニメーションです。ロード時などに使えます。
JavaScriptでアニメーションの時間を指定し、その間でカウンターを0〜1で変動させています。
進捗度合いはカウンターを整数化して表示しています。
円のメータについてはSVGで描き、その長さを正規化し、stroke-dashoffsetを初期値1からカウンターを引き算することで0に近づけ、円のメーターをアニメーションさせています。
stroke-dashoffsetが0になることで円メーターが完了しますが、0になったタイミング(カウンターが100%になったタイミング)で円メーターの線を実線にすることで、始点と終点の継ぎ目が出ないように工夫しています。
コードサンプル
HTML
<div class="loader">
<svg class="ring" viewBox="0 0 120 120">
<circle class="track" cx="60" cy="60" r="54" pathLength="1"/>
<circle class="progress" cx="60" cy="60" r="54" pathLength="1"/>
</svg>
<p class="value" aria-live="polite" aria-label="読み込み進捗">
<span class="number">0</span><span class="percent">%</span>
</p>
</div>
CSS
.loader {
--circle-dia: 4em;
position: relative;
display: grid;
place-items: center;
width: var(--circle-dia);
aspect-ratio: 1 / 1;
}
.ring {
position: absolute;
inset: 0;
transform: rotate(-90deg);
}
circle {
fill: none;
stroke-width: 8;
}
.track {
stroke: #F4F5F9;
}
.progress {
stroke: #08254f;
stroke-width: 8;
stroke-dasharray: 1;
stroke-dashoffset: 1;
stroke-linecap: butt;
shape-rendering: geometricPrecision;
}
.value .percent {
font-size: 0.8em;
}
JavaScript
document.addEventListener("DOMContentLoaded", function () {
const numberEl = document.querySelector(".number");
const progressEl = document.querySelector(".progress");
const duration = 2000;
window.runAnimation = function() {
const start = performance.now();
let last = -1;
numberEl.textContent = "0";
progressEl.style.strokeDasharray = "1";
progressEl.style.strokeDashoffset = "1";
function frame(now){
const raw = Math.min((now - start) / duration, 1);
const pct = Math.floor(raw * 100);
if (pct !== last){
numberEl.textContent = pct;
last = pct;
}
progressEl.style.strokeDashoffset = 1 - raw;
if (raw < 1) {
requestAnimationFrame(frame);
} else {
progressEl.style.strokeDasharray = "none";
progressEl.style.strokeDashoffset = "0";
}
}
requestAnimationFrame(frame);
};
runAnimation(); // ロード時に実行
});