06숫자 %
오른쪽 위 작은 숫자가 스크롤한 만큼 0에서 100까지 오른다. @property 로 정수만 보간한다.
쓰임긴 설문·튜토리얼의 진행률 표시
@property정수 보간% 붙이기

<main class="stage">
<div class="counter" role="status" aria-label="읽기 진행률">
<span class="counter__num is-demo" aria-hidden="true"></span>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$color: $subject-ink; // 숫자 색
$duration: $dur-loop;
$easing: linear; // 스크롤과 1:1로 움직이니 linear 가 맞다
@include stage($stage-yellow);
// 정수라야 애니메이션 중간값도 정수로 보간된다 (029 와 같은 기법)
@property --num {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.counter {
position: fixed;
top: $sp-6; right: $sp-6;
}
.counter__num {
--num: 0;
counter-reset: num var(--num);
display: block;
font-weight: 800;
font-size: clamp(26px, 8vw, 36px);
line-height: 1;
font-family: inherit;
font-variant-numeric: tabular-nums;
color: $color;
&::before { content: counter(num) '%'; }
// 실제 사용: 전체 문서를 스크롤한 비율이 그대로 숫자가 된다
@supports (animation-timeline: scroll()) {
animation: count-up $easing both;
animation-timeline: scroll(root);
}
}
@keyframes count-up { from { --num: 0; } to { --num: 100; } }
.counter__num.is-demo { animation: count-up-loop $duration $easing infinite; }
@keyframes count-up-loop {
0% { --num: 0; }
92% { --num: 100; }
100% { --num: 100; }
}
@media (prefers-reduced-motion: reduce) {
.counter__num, .counter__num.is-demo { animation: none !important; --num: 100; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffd23f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
@property --num {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
.counter {
position: fixed;
top: 24px;
right: 24px;
}
.counter__num {
--num: 0;
counter-reset: num var(--num);
display: block;
font-weight: 800;
font-size: clamp(26px, 8vw, 36px);
line-height: 1;
font-family: inherit;
font-variant-numeric: tabular-nums;
color: #17141a;
}
.counter__num::before {
content: counter(num) "%";
}
@supports (animation-timeline: scroll()) {
.counter__num {
animation: count-up linear both;
animation-timeline: scroll(root);
}
}
@keyframes count-up {
from {
--num: 0;
}
to {
--num: 100;
}
}
.counter__num.is-demo {
animation: count-up-loop 2s linear infinite;
}
@keyframes count-up-loop {
0% {
--num: 0;
}
92% {
--num: 100;
}
100% {
--num: 100;
}
}
@media (prefers-reduced-motion: reduce) {
.counter__num, .counter__num.is-demo {
animation: none !important;
--num: 100;
}
}import { useEffect, useState } from "react";
import styles from "./PercentCounter.module.scss";
export type PercentCounterProps = {
/** 숫자 색 */
color?: string;
};
// 실제 쓰임: 스크롤 진행률을 그대로 정수 퍼센트로 보여준다.
export default function PercentCounter({ color = "#17141a" }: PercentCounterProps) {
const [percent, setPercent] = useState(0);
useEffect(() => {
const onScroll = () => {
const max = document.documentElement.scrollHeight - window.innerHeight;
setPercent(max > 0 ? Math.min(100, Math.round((window.scrollY / max) * 100)) : 0);
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
<div className={styles.counter} role="status" aria-label="Reading progress">
<span className={styles.num} style={{ color }}>{percent}%</span>
</div>
);
}06 숫자 % — 측정 누적면적 0.872% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · CSS 프로그레스바 애니메이션 9종 — 스크롤 읽기 진행 표시
이 데모가 속한 글
CSS 프로그레스바 애니메이션 9종 — 스크롤 읽기 진행 표시CSS 프로그레스바 애니메이션은 지금까지 얼마나 읽었는지를 스크롤 위치만으로 계산해 보여주는 장치입니다. AOS·GSAP 없이, JS 0줄로 아홉 가지 형태를 모았습니다 — 상단 바, 원형 배지, 점 내비, 세로 바 이 글의 데모 전부 보기


