本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
ローディング

ローディングの終わりに、円とチェックを線で描いて完了を伝える

デモ

仕様

動作
DOM
種類
レシピ
使うもの
DrawSVGPlugin
動作確認
three 0.186.0・gsap 3.15.0
公開日

しくみと調整

円とチェックマークを 1 本の線として描き、描き終えたところへ面をはめ込みます。DrawSVGPlugin を使うと stroke-dasharray の値を自分で計算しなくて済み、0% から100% まで指定するだけで線が伸びていきます。

円は3時の方向から時計回りに描かれる仕様なので、rotate(-90) を掛けて12時から描き始めています。線の色は面より明るくしてあり、差し込んだ面の上でもチェックマークがはっきり読めます。

丸くした線の端は、長さを0% まで縮めても先端に点として残ってしまうので、描き終わるまでは隠しておき、描き始める瞬間に表示へ切り替えています。

面の色や線の太さ、描く速さは差し替えられます。送信の完了やタスクの完了など、結果をひと目で伝えたい場面に向いています。

コード

HTML
<!-- 完了バッジ。線を描き終えたら面を差し込む。SVG は飾りなので aria-hidden -->
<div class="check-badge">
  <svg class="check-badge__svg" viewBox="0 0 200 200" aria-hidden="true">
    <circle class="check-badge__disk" cx="100" cy="100" r="72"></circle>
    <circle class="check-badge__ring" cx="100" cy="100" r="82" transform="rotate(-90 100 100)"></circle>
    <path class="check-badge__check" d="M70 102 L90 123 L134 77"></path>
  </svg>
  <!-- 読み上げ用。最初から文が入っていると読み上げられないので空にしておき、show() が data-message の文を入れる -->
  <span class="check-badge__text" role="status" data-message="完了しました"></span>
</div>

CSS
.check-badge {
  --size: 200px;      /* バッジの直径 */
  --ink: #eeece6;     /* 円とチェックの線の色 */
  --success: #4f8a64; /* 差し込む面の色。線より明るくして、面の上のチェックを読めるようにする */
  --ground: #111111;  /* 地の色 */
  display: grid;
  place-items: center;
  min-height: 60vh;
  padding: 96px 6vw;
  background: var(--ground);
}

.check-badge__svg {
  display: block;
  width: var(--size);
  height: var(--size);
}

/* 描き終えるまで隠しておく。JS が show() で見せる */
.check-badge__ring,
.check-badge__check,
.check-badge__disk {
  visibility: hidden;
}

.check-badge__disk { fill: var(--success); }

.check-badge__ring {
  fill: none;
  stroke: var(--ink);
  stroke-width: 7;
  stroke-linecap: round;
}

.check-badge__check {
  fill: none;
  stroke: var(--ink);
  stroke-width: 9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 読み上げにだけ届く文言。画面には出さない(文は show() が入れる) */
.check-badge__text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

JavaScript
import { gsap } from "gsap";
import { DrawSVGPlugin } from "gsap/DrawSVGPlugin";

gsap.registerPlugin(DrawSVGPlugin);

const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

function createBadge(root) {
  const ring = root.querySelector(".check-badge__ring");
  const check = root.querySelector(".check-badge__check");
  const disk = root.querySelector(".check-badge__disk");
  const text = root.querySelector(".check-badge__text");
  const SPEED = reduceMotion ? 20 : 1; // 動きを減らす設定では、ほぼ一瞬で切り替える
  gsap.set([ring, check], { drawSVG: "0%" });
  gsap.set(disk, { scale: 0, transformOrigin: "50% 50%" });

  return {
    // 完了したら呼ぶ。円 → チェック → 面の順に描き込む
    show() {
      return gsap
        .timeline()
        .set([ring, check, disk], { visibility: "visible" })
        .to(ring, { drawSVG: "100%", duration: 1.1, ease: "power2.inOut" })
        .to(check, { drawSVG: "100%", duration: 0.55, ease: "power2.out" }, 0.88)
        .to(disk, { scale: 1, duration: 0.66, ease: "back.out(1.6)" }, 1.21)
        // 読み上げの文は、チェックを描き終えた所で入れる(role="status" は、後から入った文だけを読み上げる)
        .call(() => (text.textContent = text.dataset.message), null, 1.43)
        .timeScale(SPEED);
    },

    // バッジを消す。線を終点側へ縮め、面を引っ込めてから取り除く
    hide() {
      return gsap
        .timeline({ onComplete: () => root.remove() })
        .to([ring, check], { drawSVG: "100% 100%", duration: 0.66, ease: "power2.in" })
        .to(disk, { scale: 0, duration: 0.55, ease: "power2.in" }, "<0.11")
        .timeScale(SPEED);
    },
  };
}

export const badge = createBadge(document.querySelector(".check-badge"));

// 使い方の例: ページの読み込みが終わったら、完了を見せる。
// 案件では、送信が成功した所などで badge.show() を呼び、閉じるかタイマーで badge.hide() を呼ぶ
if (document.readyState === "complete") badge.show();
else window.addEventListener("load", () => badge.show(), { once: true });

インタラクションデザインについて、
お気軽にご相談ください。

ここに並べているのは、Web サイトの中で動く UI のサンプルです。新しく作るサイトに組み込むことも、いま公開中のサイトに、ボタンやヒーロー、スクロールの演出だけを足すこともできます。設計から実装までの進め方はWeb サイト制作、端末ごとの見え方や表示速度の考え方はレスポンシブウェブサイトのページにまとめています。映像として作る動きをお探しの場合はモーショングラフィックスをご覧ください。