テキスト・数字 #006
カウントアップ Count-up
数字が0から目標値へ増えていく
0から12,800までの数字が、最初は速く、終わりに近づくほどゆっくり増えて止まります。少し止まってから繰り返します。
調整する
値を変えるとプレビューに反映され、「プロンプトをコピー」「コードをコピー」も調整後の内容になります。
AIへの頼み方
実績の数字をカウントアップで見せて。2秒で、最後はゆっくり止まる感じ。
動きの仕様
- 0 → 目標値を約2.2秒で増やす。進み方は ease-out(1 − (1−p)^3)
- 数字は3桁区切りで表示し、等幅数字(tabular-nums)で幅のブレを防ぐ
- requestAnimationFrame で更新し、画面外では止める
- prefers-reduced-motion の環境では最初から目標値を表示する
使いどころ
導入実績・利用者数・達成率など、数字を印象づけたいとき。
コピーされるプロンプト全文を見る
「カウントアップ(Count-up)」の動きを実装してください。 OmochiX Learn の動く見本 #006(テキスト・数字)です。 頼み方の例: 実績の数字をカウントアップで見せて。2秒で、最後はゆっくり止まる感じ。 どんな動きか: 数字が0から目標値へ増えていく 見本で起きること: 0から12,800までの数字が、最初は速く、終わりに近づくほどゆっくり増えて止まります。少し止まってから繰り返します。 仕様: - 0 → 目標値を約2.2秒で増やす。進み方は ease-out(1 − (1−p)^3) - 数字は3桁区切りで表示し、等幅数字(tabular-nums)で幅のブレを防ぐ - requestAnimationFrame で更新し、画面外では止める - prefers-reduced-motion の環境では最初から目標値を表示する 使いどころ: 導入実績・利用者数・達成率など、数字を印象づけたいとき。 調整した値: - 目標値は12800(既定) - 0から目標値まで2.2sで増やす(既定) - 進み方は「最後にゆっくり」(既定) - 数字の大きさ: 56px(既定) 実装の条件: - HTML / CSS(必要なら素のJavaScript)で、外部ライブラリは使わない - 見本の形・タイミング・イージングの数値はそのまま使い、文字・色・素材だけ今作っているものに合わせる - prefers-reduced-motion: reduce の環境では動きを止めるか最小限にする - 使った技術: CSS / JavaScript 見本(動くプレビューと参考コード): https://omochix.com/learn/motion/count-up/
コード
プレビューで動いているものと同じコードです。HTMLに貼り付ければそのまま動きます。
HTML / CSS / JavaScript
<!-- カウントアップ (Count-up) | OmochiX Learn 動く見本 #006 | https://omochix.com/learn/motion/count-up/ -->
<style>
.cu{display:flex;align-items:baseline;gap:10px;margin:0;color:var(--text)}
.cu__n{font:800 var(--p-size,56px)/1 system-ui,sans-serif;letter-spacing:-.04em;font-variant-numeric:tabular-nums;min-width:4.2em;text-align:right}
.cu__u{font:600 16px/1 system-ui,sans-serif;color:var(--muted)}
</style>
<p class="cu"><span class="cu__n" data-target="12800">0</span><span class="cu__u">users</span></p>
<script>
var omx = window.omx = window.omx || (function () {
// OmochiX の見本用の最小ランタイム。animate() の処理をすべて 1 本の
// requestAnimationFrame にまとめ、タブが隠れている間と
// prefers-reduced-motion: reduce のときは止める。
var fns = [], frame = 0, started = 0, stoppedAt = 0, lost = 0;
var media = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;
function stopped() { return (media && media.matches) || document.hidden; }
function tick(now) {
frame = 0;
if (stopped()) { stop(); return; }
var t = Math.max(0, now - started - lost) / 1000; // rAF の時刻は要求時より前のことがある
for (var i = 0; i < fns.length; i++) { try { fns[i](t); } catch (e) { /* 他の見本は止めない */ } }
frame = window.requestAnimationFrame(tick);
}
function stop() {
if (frame) { window.cancelAnimationFrame(frame); frame = 0; }
if (started && !stoppedAt) stoppedAt = performance.now();
}
function sync() {
api.reduced = !!(media && media.matches);
if (stopped()) { stop(); return; }
if (frame || !fns.length) return;
var now = performance.now();
if (!started) started = now; else if (stoppedAt) lost += now - stoppedAt;
stoppedAt = 0;
frame = window.requestAnimationFrame(tick);
}
var api = {
root: document,
reduced: !!(media && media.matches),
animate: function (fn) { if (typeof fn === 'function') { fns.push(fn); sync(); } },
param: function (key, fallback) { var p = window.omxParams || {}; return Object.prototype.hasOwnProperty.call(p, key) ? p[key] : fallback; },
onParams: function () {}
};
document.addEventListener('visibilitychange', sync);
if (media && media.addEventListener) media.addEventListener('change', sync);
return api;
}());
var el=omx.root.querySelector('.cu__n');var loopGap=1.2;var base=0;var lastT=0;function ease(p,kind){if(kind==='linear')return p;if(kind==='inout')return p<.5?4*p*p*p:1-Math.pow(-2*p+2,3)/2;return 1-Math.pow(1-p,3);}function target(){return Number(omx.param('target',Number(el.getAttribute('data-target'))||12800));}function show(n){el.textContent=Math.round(n).toLocaleString('ja-JP');}omx.onParams(function(){base=lastT;});omx.animate(function(t){lastT=t;var duration=Number(omx.param('duration',2.2));var kind=omx.param('easing','out');var loop=duration+loopGap;var p=Math.min(((t-base)%loop)/duration,1);show(ease(p,kind)*target());});if(omx.reduced)show(target());
</script>