Progress bar

프로그레스 바

A read-only bar whose fill length reports how much of a task is complete.

Also known as: Progress indicatorLoading bar
···
html
<div class="pbw">
  <div class="pbtop"><span>업로드 중</span><b id="pbv">0%</b></div>
  <div class="pb" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="pbfill" id="pbf"></div></div>
  <div class="pb2"><div class="pb2fill"></div></div>
</div>
css
.pbw{width:min(230px,88%);display:grid;gap:16px}
.pbtop{display:flex;justify-content:space-between;font-size:12px;color:var(--muted)}
.pbtop b{color:var(--fg)}
.pb{height:8px;border-radius:5px;background:var(--line);overflow:hidden}
.pbfill{height:100%;width:0%;background:var(--accent);border-radius:5px;transition:width .3s linear}
.pb2{height:4px;border-radius:3px;background:var(--line);overflow:hidden;position:relative}
.pb2fill{position:absolute;top:0;bottom:0;width:35%;background:var(--accent-2,#f25c8a);border-radius:3px;animation:indet 1.3s ease-in-out infinite}
@keyframes indet{0%{left:-35%}100%{left:100%}}
js
const pbf = document.getElementById('pbf'), pbv = document.getElementById('pbv'), pb = document.querySelector('.pb');
let v = 0;
setInterval(() => {
  v = (v + 4) % 104;
  const cv = Math.min(v, 100);
  pbf.style.width = cv + '%'; pbv.textContent = cv + '%'; pb.setAttribute('aria-valuenow', String(cv));
}, 140);

Keep aria-valuenow/min/max on role="progressbar" updated live. When the exact percentage is unknowable, omit aria-valuenow entirely and show a continuously moving "indeterminate" stripe instead — at that point it functionally overlaps with a spinner.

The line between the two is whether you know how long it'll take. A determinate task like a file upload, where remaining bytes are known, is better served by a progress bar's extra information; a task with no knowable end, like waiting on a server response, is more honest as a spinner. The difference from a skeleton is that a skeleton fakes the shape of upcoming content to speed up perceived load, while a progress bar reports the numeric progress itself.

Rather than vanishing the instant it hits 100%, holding briefly on a completed state gives more confidence that the task actually finished.