OmochiXを検索

Esc で閉じる

テキスト・数字 #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>