GODRICH
#cssアニメーション#ボタン#ローディング#トランジション#スクロール#ダッシュボード#実用ui#デザイントレンド

css download button 9パターン — 沈み・満ち・ファイルが飛ぶボタン

css download button をラベルの入れ替えだけで作ると、矢印は硬く、進捗は段差になり、ファイルの行き先も見えない — 01番・02番・03番が計算で解く。取得ボタン一つを、押す・満ちる・届く・終わる・失敗するまで動きで見せる UI です。

ダウンロードボタンの九つの場面をこのページで見る

自動再生 · タイルを押すとその項目へ · すべて1つのzip

css download button 9パターン — バネ・進捗曲線・経路を計算すると取得が感じられる

九つは、取得が一回流れていく順に並べました。01 は押すと沈む矢印、02 は進捗カーブで満ちるリング、03 はトレイへ飛ぶファイルで、04 は受け取ったサイズを数えるチップ、05 は上がる液面、06 は矢印がチェックに変わる完了です。07 は形式を選ぶ分割ボタン、08 は失敗して揺れ、もう一度試すボタン、09 はカーソルへ寄って光る第一印象のボタンです。

こんな画面で使います

資料ダウンロードのページや製品紹介の取得ボタンのように、一度押してファイルを持ち帰ってもらう場所で使います。容量の大きい資料を渡す画面なら 02 と 04 の進捗表示が、受け取ったファイルを溜めておく画面なら 03 のトレイが、形式が複数ある文書なら 07 の分割ボタンが先に要ります。どれも取得の状態を数値一つにまとめ、その数値から形を計算する点は同じです。

隣の記事とどこが違うか

css ボタン 押したら変わる 9選 — 状態遷移の実装は押したあとの状態の移り方を、ダウンロード 進捗バー 9選 — 値がパーセントで更新される9つの方式は取得中のファイルが一覧に並ぶ画面を扱います。この記事は、ボタン一つが押下・進捗・到着・完了・失敗をそれぞれどんな計算で動かすかに九つの場面を使いました。

技法別のコードで見るダウンロードボタン

九つの場面はどれも標準の button 要素で、動きは CSS の遷移ではなく、JS がフレームごとに計算した値で塗っています。入力がないあいだは .is-demo が付いていて二秒周期で同じ動きを繰り返し、最初の入力が来るとその場で外れ、同じ計算が入力を受けます。ライブラリと CDN は使わず、下のコードはソースの連続した区間をそのまま載せました。

01押すと沈む矢印

押すと矢印が SINK_PX の10px沈み、押した横位置の側へ最大14度傾きます。どちらもバネの式を8ms以下の小刻みなステップで積分して求め、SPRING_K 120・SPRING_DAMP 9 の減衰比は約0.41なので沈み量の約24%を行き過ぎてから戻り、取得ボタンの基本の押し心地に向きます。測定は累積面積13.3%、強度平均72.3、動いたフレーム23/23です。

押すと沈む矢印
新しいタブで開く

01 · 押すと沈む矢印 — 計測 累積面積 13.29% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

SINK_PXSPRING_KSPRING_DAMP
  function integrate(dt, g) {
    var n = Math.ceil(dt / 0.008);
    var h = dt / n;
    for (var i = 0; i < n; i += 1) {
      vy += (-SPRING_K * (y - g.depth) - SPRING_DAMP * vy) * h;
      y += vy * h;
      vt += (-SPRING_K * (tilt - g.lean * TILT_MAX) - SPRING_DAMP * vt) * h;
      tilt += vt * h;
    }
  }

  function render() {
    var p = clamp(y / SINK_PX, -0.3, 1);
    icon.style.transform = 'translateY(' + y.toFixed(2) + 'px) rotate(' + tilt.toFixed(2) + 'deg)';
    btn.style.transform = 'translateY(' + (y * 0.3).toFixed(2) + 'px)';
    btn.style.setProperty('--p', p.toFixed(3));
    yEl.textContent = y.toFixed(1);
    tiltEl.textContent = tilt.toFixed(1);
  }

02進捗カーブで満ちていく枠のリング

太いリングは CURVE_POW 2 の曲線 1 - (1 - u)^CURVE_POW に従い、内側の細いリングは均一な進み方 u のままで、二つの差 LEAD は u 0.5 で最大25ポイントまで開きます。リングとボタン内の塗りが同じ進捗を読み、aria-valuenow を毎フレーム更新するので、大きなファイルの取得案内のように出足が速く見えてほしい場所に使えます。測定は累積面積11.1%、強度平均117.5、動いたフレーム19/23です。

進捗カーブで満ちていく枠のリング
新しいタブで開く

02 · 進捗カーブで満ちていく枠のリング — 計測 累積面積 11.07% · 動いたフレーム 19/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

CURVE_POWRING_RRUN_MS
  function render(now) {
    var s = startOf(now);
    var u = s === null ? 0 : Math.max(0, Math.min(1, (now - s) / RUN_MS));
    if (reduce && runStart === 'done') u = 1;
    var p = ringCurve(u);
    var pct = Math.round(p * 100);
    ring.style.strokeDashoffset = String((100 - p * 100).toFixed(2));
    ghost.style.strokeDashoffset = String((100 - u * 100).toFixed(2));
    ring.style.opacity = p < 0.004 ? '0' : '1';
    ghost.style.opacity = u < 0.004 ? '0' : '1';
    btn.style.setProperty('--f', p.toFixed(3));
    pctEl.textContent = pct + '%';
    leadEl.textContent = String(Math.round((p - u) * 100));
    labelEl.textContent = u >= 1 ? '完了' : (u > 0 ? '受信中' : 'ダウンロード');
    bar.setAttribute('aria-valuenow', String(pct));
    bar.setAttribute('aria-valuetext', pct + '%');
  }

03トレイへ飛んで収まるファイル

ファイルのアイコンが FLY_MS 700ms のあいだ二次ベジェ曲線をたどり、最大 ARC_HEIGHT 56px の弧を描きながら回って小さくなり、トレイの近くで消えます。着くとトレイが TRAY_BOUNCE 14px 押し下がり、減衰比約0.37のバネで何度か揺れて戻って個数が一つ増えるので、受け取ったファイルの行き先を見せる場面に使います。測定は累積面積11.8%、強度平均101.2、動いたフレーム21/23です。

トレイへ飛んで収まるファイル
新しいタブで開く

03 · トレイへ飛んで収まるファイル — 計測 累積面積 11.791% · 動いたフレーム 21/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

FLY_MSARC_HEIGHTTRAY_BOUNCE
  function renderFile(now) {
    if (flightStart === null) { file.style.opacity = '0'; return; }
    var t = Math.min(1, (now - flightStart) / FLY_MS);
    var e = ease(t);
    var g = geometry();
    var cx = g.x + 2 * ARC_HEIGHT;
    var cy = (g.y0 + g.y2) / 2;
    var x = (1 - e) * (1 - e) * g.x + 2 * (1 - e) * e * cx + e * e * g.x;
    var y = (1 - e) * (1 - e) * g.y0 + 2 * (1 - e) * e * cy + e * e * g.y2;
    var rot = 28 * Math.sin(Math.PI * e);
    var sc = 1 - 0.45 * e;
    file.style.opacity = t > 0.9 ? String((1 - t) * 10) : '1';
    file.style.transform = 'translate(' + (x - 14).toFixed(1) + 'px,' + (y - 14).toFixed(1) + 'px) rotate(' + rot.toFixed(1) + 'deg) scale(' + sc.toFixed(3) + ')';
  }

  function renderTray() {
    tray.style.transform = 'translateY(' + ty.toFixed(2) + 'px)';
    tray.style.setProperty('--h', Math.max(0, Math.min(1, ty / TRAY_BOUNCE)).toFixed(3));
    countEl.textContent = String(count);
  }

04受け取ったサイズを数え上げるチップ

受信サイズは TARGET_MB 48 に COUNT_EASE 3乗の減速曲線を掛けて上がり、残り時間は残量を、ここまでの平均速度で割って出します。48MBと2分はデモ用の定数で、残り時間は約40秒から始まって0:00へ減るので、サイズと残り時間を並べて書く場所の型として使います。測定は累積面積18.6%、強度平均80.9、動いたフレーム19/23です。

受け取ったサイズを数え上げるチップ
新しいタブで開く

04 · 受け取ったサイズを数え上げるチップ — 計測 累積面積 18.608% · 動いたフレーム 19/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

COUNT_EASETARGET_MBETA_MIN
  function render(now) {
    var s = startOf(now);
    var u = s === null ? 0 : Math.max(0, Math.min(1, (now - s) / RUN_MS));
    if (reduce && finished) u = 1;
    var got = TARGET_MB * (1 - Math.pow(1 - u, COUNT_EASE));
    var eta = '--:--';
    if (u > 0) {
      var elapsedSec = Math.max(u, 0.004) * ETA_MIN * 60;
      var avg = Math.max(got, 0.01) / elapsedSec;
      var left = Math.round((TARGET_MB - got) / avg);
      eta = Math.floor(left / 60) + ':' + two(left % 60);
    }
    root.style.setProperty('--f', (got / TARGET_MB).toFixed(3));
    gotEl.textContent = got.toFixed(1);
    etaEl.textContent = eta;
    labelEl.textContent = u >= 1 ? '完了' : (u > 0 ? '受信中' : 'ダウンロード');
    if (u >= 1 && !announced) { announced = true; statusEl.textContent = 'ダウンロード完了'; }
    if (u < 1 && announced) { announced = false; statusEl.textContent = ''; }
  }

05進捗に合わせて上がる液面

水面は48区間(点49個)を二つのサイン波の和でつないだ SVG の経路で、振幅 amp は液面が上がるほど小さくなり、満ちると穏やかになります。液面は目標の進捗を LEVEL_LERP 6 の指数補間で追うので、進行状況を絵で見せたい CTA に向きます。測定は累積面積12.0%、強度平均130.8、動いたフレーム23/23です。

進捗に合わせて上がる液面
新しいタブで開く

05 · 進捗に合わせて上がる液面 — 計測 累積面積 12.04% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

WAVE_AMPWAVE_FREQLEVEL_LERP
  function draw(phase) {
    var reach = WAVE_AMP * 1.5;
    var base = -reach + (H + 2 * reach) * (1 - level);
    var amp = WAVE_AMP * (1 - 0.7 * level);
    var d = 'M0 ' + H;
    for (var i = 0; i <= POINTS; i += 1) {
      var x = (i / POINTS) * W;
      var a = 2 * Math.PI * WAVE_FREQ * (x / W);
      var y = base + amp * (Math.sin(a + phase) + 0.5 * Math.sin(2 * a - 1.3 * phase));
      d += 'L' + x.toFixed(1) + ' ' + y.toFixed(2);
    }
    d += 'L' + W + ' ' + H + 'Z';
    pathEl.setAttribute('d', d);
    var pct = Math.round(level * 100);
    pctEl.textContent = pct + '%';
    labelEl.textContent = level > 0.995 ? '完了' : (level > 0.01 ? '受信中' : 'ダウンロード');
    levelEl.textContent = level.toFixed(2);
    ampEl.textContent = amp.toFixed(1);
  }

06線の長さで矢印がチェックに変わる完了

矢印とチェックの二本の線の stroke-dashoffset を進行値 p 一つで計算し、p 0.5 までに矢印の線が縮み、0.4 からチェックの線が引かれ、ラベルは0.5で替わります。ボタン幅は見えない物差しの要素の offsetWidth でラベルの幅を測り、WIDTH_LERP 10 で寄せるので、取得完了の確認に合います。測定は累積面積11.6%、強度平均50.8、動いたフレーム18/23です。

線の長さで矢印がチェックに変わる完了
新しいタブで開く

06 · 線の長さで矢印がチェックに変わる完了 — 計測 累積面積 11.569% · 動いたフレーム 18/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

STROKE_LENCHECK_MSWIDTH_LERP
  function render(want) {
    var shrink = clamp(p / 0.5, 0, 1);
    var draw = clamp((p - 0.4) / 0.6, 0, 1);
    arrow.style.strokeDashoffset = String((STROKE_LEN * shrink).toFixed(2));
    check.style.strokeDashoffset = String((STROKE_LEN * (1 - draw)).toFixed(2));
    label.textContent = p >= 0.5 ? '完了' : 'ダウンロード';
    label.style.opacity = String(Math.abs(2 * p - 1).toFixed(2));
    btn.style.setProperty('--p', p.toFixed(3));
    btn.style.width = width.toFixed(1) + 'px';
    pEl.textContent = p.toFixed(2);
    wEl.textContent = String(Math.round(width));
    if (p >= 1 && !announced) { announced = true; statusEl.textContent = 'ダウンロード完了'; }
    if (p <= 0 && announced) { announced = false; statusEl.textContent = ''; }
  }

07形式を選ぶ分割ボタン

FORMATS の三つの項目が MENU_STAGGER 70ms ずつ遅れて easeOutBack で広がり、選んだ形式は高さ24pxのラベル窓で、古い文字が LABEL_RISE 24px 上へ抜けて新しい文字が下から上がります。トグルは ArrowDown で開き、矢印キーで項目を移り、Escape で閉じるので、PDF や PNG のように形式が分かれる取得に使います。測定は累積面積17.7%、強度平均90.6、動いたフレーム19/23です。

形式を選ぶ分割ボタン
新しいタブで開く

07 · 形式を選ぶ分割ボタン — 計測 累積面積 17.706% · 動いたフレーム 19/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

MENU_STAGGERFORMATSLABEL_RISE
  function render() {
    var s = open * OPEN_MS;
    var visible = open > 0.001 || wantOpen;
    for (var i = 0; i < items.length; i += 1) {
      var q = outBack(clamp((s - i * MENU_STAGGER) / ITEM_MS, 0, 1));
      var o = clamp(q, 0, 1);
      items[i].style.opacity = o.toFixed(3);
      items[i].style.transform = 'translateY(' + ((1 - q) * -16).toFixed(2) + 'px) scale(' + (0.8 + 0.2 * q).toFixed(3) + ')';
      items[i].style.visibility = visible ? 'visible' : 'hidden';
      items[i].setAttribute('tabindex', wantOpen ? '0' : '-1');
      items[i].classList.toggle('is-picked', i === wantFmt);
    }
    menu.setAttribute('aria-hidden', wantOpen ? 'false' : 'true');
    toggle.setAttribute('aria-expanded', wantOpen ? 'true' : 'false');
    toggle.style.setProperty('--o', open.toFixed(3));
    root.style.setProperty('--k', (1 - rise).toFixed(3));
    oldEl.style.transform = 'translateY(' + (-LABEL_RISE * outCubic(rise)).toFixed(2) + 'px)';
    newEl.style.transform = 'translateY(' + (LABEL_RISE * (1 - outBack(rise))).toFixed(2) + 'px)';
    oldEl.style.opacity = String((1 - rise).toFixed(2));
    textEl.textContent = FORMATS[wantFmt];
  }

08失敗して減衰し再試行するボタン

失敗すると bar 要素一つが translateX で SHAKE_AMP 14px から始まり、毎秒 SHAKE_DECAY 5 の割合で縮みながら4.5Hzで揺れ、続いて REWIND_MS 500ms でリングが最初へ巻き戻ってラベルが再試行に替わります。実際の入力では一回目が失敗し二回目が最後まで進むようコードが決めたデモなので、途切れた取得を復旧する画面の型としてだけ使います。測定は累積面積10.9%、強度平均135.5、動いたフレーム23/23です。

失敗して減衰し再試行するボタン
新しいタブで開く

08 · 失敗して減衰し再試行するボタン — 計測 累積面積 10.896% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

SHAKE_AMPSHAKE_DECAYREWIND_MS
    var t = now - s;
    if (t < RUN_MS) {
      var u = outQuad(t / RUN_MS);
      return { p: res === 'fail' ? FAIL_AT * u : u, x: 0, e: 0, label: '受信中', glyph: ARROW, note: '' };
    }
    if (res === 'ok') return { p: 1, x: 0, e: 0, label: '完了', glyph: ARROW, note: 'ダウンロード完了' };
    var tau = (t - RUN_MS) / 1000;
    var rw = clamp((t - RUN_MS - REWIND_DELAY) / REWIND_MS, 0, 1);
    return {
      p: FAIL_AT * (1 - inOut(rw)),
      x: SHAKE_AMP * Math.exp(-SHAKE_DECAY * tau) * Math.sin(2 * Math.PI * SHAKE_HZ * tau),
      e: 1,
      label: rw >= 1 ? '再試行' : '失敗',
      glyph: BANG,
      note: 'ダウンロードが途切れました'
    };

09カーソルへ寄って光るボタン

ボタンはカーソルと中心の距離に PULL_RATE 0.12 を掛けた量だけ、最大 LEAN_MAX 10px まで引かれ、幅 SHEEN_W 64px の光の帯はカーソルの横位置を指数補間で追います。カーソルを見る範囲はボタンではなくその周りの最大280x144の領域なので、ランディングページの主 CTA の第一印象に使います。測定は累積面積18.2%、強度平均82.3、動いたフレーム23/23です。

カーソルへ寄って光るボタン
新しいタブで開く

09 · カーソルへ寄って光るボタン — 計測 累積面積 18.191% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

PULL_RATESHEEN_WLEAN_MAX
  function goal(now) {
    var w = btn.offsetWidth;
    var h = btn.offsetHeight;
    var d = null;
    if (root.classList.contains('is-demo') && now >= START_MS) {
      var a = 2 * Math.PI * ((now - START_MS) % CYCLE_MS) / CYCLE_MS;
      d = { x: ORBIT_X * Math.cos(a), y: ORBIT_Y * Math.sin(a) };
    } else if (cursor) {
      d = cursor;
    }
    if (kbFocus && !d) return { lx: 0, ly: 0, sx: w / 2, a: 1, gx: 50, gy: 50 };
    if (!d) return { lx: 0, ly: 0, sx: -SHEEN_W * 2, a: 0, gx: 50, gy: 50 };
    return {
      lx: clamp(d.x * PULL_RATE, -LEAN_MAX, LEAN_MAX),
      ly: clamp(d.y * PULL_RATE, -LEAN_MAX, LEAN_MAX),
      sx: clamp(d.x + w / 2, -SHEEN_W, w + SHEEN_W),
      a: 1,
      gx: clamp((d.x + w / 2) / w * 100, -20, 120),
      gy: clamp((d.y + h / 2) / h * 100, -40, 140)
    };
  }

値が場面を変えるところ — バネの強さ・曲線の指数・振幅

定数三つが、押したときの揺れ、進捗の先行、水面の揺れをほぼ決めます。css download button animation を作るときは、曲線やバネの式そのものより、この値を一つ動かして見るほうが場面の性格をずっと早く変えられます。下の数値は各項目を二秒レンダリングして24枚から取り、動いたフレームの分母はコマ間の間隔である23です。

項目 累積面積 % 強度平均 動いたフレーム
01 沈む矢印 13.3% 72.3 23/23
02 進捗カーブのリング 11.1% 117.5 19/23
03 飛ぶファイル 11.8% 101.2 21/23
04 サイズのチップ 18.6% 80.9 19/23
05 液面 12.0% 130.8 23/23
06 チェックの線 11.6% 50.8 18/23
07 分割メニュー 17.7% 90.6 19/23
08 失敗の揺れ 10.9% 135.5 23/23
09 寄る光沢 18.2% 82.3 23/23

累積面積が10%を下回る項目はありません。動いたフレームが23に満たないのは 02・03・04・06・07 で、理由はソースで確かめていないので、測定値だけを書きます。

バネの強さが行き過ぎを決める

01 の減衰比は SPRING_DAMP の9を、2と SPRING_K の平方根の積で割った値です。120では約0.41で、沈み量10pxの約24%にあたる2.4pxを行き過ぎます。SPRING_DAMP を変えずに SPRING_K だけを240へ上げると減衰比が約0.29に下がり、行き過ぎは約39%に増えます。

曲線の指数が先行を決める

02 の LEAD は曲線の進捗から均一な進捗を引いた値なので、指数2では u 0.5 のとき最大25ポイントです。CURVE_POW を4へ上げると、u 約0.37で約47ポイントまで開きます。曲線は均一な進み方より先行するだけで、遅れることはありません。

振幅が水面の揺れを決める

05 は amp = WAVE_AMP (1 - 0.7 level) なので、液面0.5で WAVE_AMP が6なら振幅は約3.9pxです。12へ上げると同じ液面で約7.8pxになり、満ちるほど振幅が縮む関係はそのままです。

どこで壊れるか — 進捗が逆戻りするとき・狭いボタン・キーボードだけのとき

進捗が逆戻りすると液面も下がる

02 と 04 は時間から進捗を計算するので逆戻りしません。05 は目標の進捗が下がると液面が LEVEL_LERP で下がり、パーセントの文字も一緒に減ります。デモが周期の終わりに0へ戻るとき液面が抜けるのがそれです。実際の進捗を入れるときは、入力が増えるだけの値かどうかを先に確かめてください。

ラベルが長いと幅が足りない

06 は幅をラベルの実測幅で取り直しますが、max-width: 100% とはみ出しの非表示がかかっているので、英語や日本語のように長いラベルへ替えると端が切れることがあります。07 は形式の三つが同じ比率なので、幅が260px未満になると文字が窮屈になります。

キーボードだけだと傾きも引き寄せもない

01 はキーで押すと傾きの目標を0にするので、ポインターの位置から来る傾きがありません。09 はフォーカスだけではボタンが引かれず、光の帯だけが中央に残ります。07 は閉じた項目を visibility: hidden と tabindex="-1" で外して、フォーカスが入らないようにしています。

デモの値を実際の取得にそのまま使わない

04 の48MBと2分、08 の失敗はデモ用に決めた値です。実際の速度は一定ではないので、平均速度で出した残り時間は開始直後に大きく外れ、08 は一回目の失敗と二回目の成功をコードが決めているので、応答の結果に差し替えて使います。03 は geometry() が座標をフレームごとに読み直すので、飛行中にレイアウトが動いても追従します。ただ横の位置はボタンの箱の幅の半分に固定されているため、箱の中央を外れた配置ではファイルの経路が実際の位置とずれます。

コード全体と SCSS を自分で動かすなら、圧縮ファイルを落としてパスワード f24sfs72 で開きます。九つのフォルダそれぞれに、download button html css js で組んだデモのページとスタイルが入っています。

変形三つとアクセシビリティ

三つの定数を動かした結果

項目 定数 値 感じ
01 SPRING_K 120 → 240 減衰比が約0.41から0.29へ下がり、行き過ぎが沈み量の24%から39%へ増えて、揺れが目立ちます
02 CURVE_POW 2 → 4 均一な進み方との差が最大25ポイントから約47ポイントへ開き、終盤はより長くゆっくり進みます
05 WAVE_AMP 6 → 12 液面0.5での振幅が約3.9pxから7.8pxへ増えて、波打つ水に見えます

キーボードと reduce のときの動き

九つの場面はどれも標準の button 要素なので Tab で届き、SCSS には九つすべてに :focus-visible の輪郭線があります。Enter と Space は標準の click が受け、01 は keydown と keyup で押下と解放を別に受けます。07 も keydown でメニューを受け、ArrowDown で開いて矢印キーで移り、Escape で閉じます。prefers-reduced-motion の分岐は九つすべてにあり、reduce のときは requestAnimationFrame のループを始めず、入力が来た瞬間に目標の値をそのまま塗ります。そのため 01 の沈みと 09 の追従は補間なしで目標の位置へ直接移り、03 はファイルを飛ばさず個数だけが増え、05 は液面がすぐ満タンになります。進捗の状態は 02 と 08 が role="progressbar" で、03・04・06・08 が role="status" で伝え、08 は色ではなく文字とびっくりマークのアイコンで失敗を示します。

html css download button はラベルを替えるだけで足りるか?

取得が短く、一度押して終わるファイルなら足ります。ただしラベルの入れ替えだけでは、押したときの揺れも、進捗の先行も、ファイルの行き先も見せられないので、大きなファイルや何度も受け取る画面にだけ、上の計算を足せば十分です。

取得以外のボタンの反応が欲しいときは、隣の記事へ進んでください。押し込みが戻る動きは ボタン 押し込み UI 9選 — 押し込みの値が戻る計算の9通りに、キーフレームで作るコピペ向けのボタン集は 【コピペOK】CSS ボタン アニメーション 9選(SCSS + React)にあります。

css download button を作る前によくある質問

進捗を全部 JS で計算すると重くないですか?

九つの場面は遷移もキーフレームも使わず、フレームごとに数値を計算してスタイルの値をいくつか塗る方式です。デモが回るのは入力がないあいだだけで、reduce のときはループ自体を始めないので、ボタン一つの仕事は小さく済みます。

tailwind css download button でも作れますか?

この記事のコードは素の CSS と JS で、Tailwind は使っていません。動きはクラスではなく JS が計算した値から出るので、マークアップのクラス名を別の方式に替えても、計算の区間はそのまま移して使えます。

取得の進捗を実際の値につなぐには?

02・04・05・08 の進捗を、時間の代わりに受け取ったバイトの割合へ差し替えます。05 の液面は目標が下がると一緒に下がるので入力が増えるだけかを確かめ、04 の残り時間の式は、実際の速度が一定でないときは区間ごとの平均に替えたほうが安定します。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。