本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
フォーム

チェックボックスにチェックが描かれる

デモ

操作:クリック。 「さわってみる」を押すと自動再生が止まり、マウスで動かせます。

仕様

用途
フォーム
動作
DOM
種類
レシピ
使うもの
DrawSVGPlugin
動作確認
three 0.186.0・gsap 3.15.0
公開日

しくみと調整

押すと、箱が一度縮んでから弾んで戻り、そのあいだに枠と地が成功の緑に塗られて、白いチェックの線が描かれます。外すときは同じタイムラインを逆再生するので、線が巻き戻ってから地が抜けます。

箱は 0.1 秒で 0.86 倍に縮め、0.5 秒の back.out(3) で戻します。塗りは縮み始めてすぐ 0.15 秒で入れ替え、線は 0.18 秒後から 0.35 秒かけて描きます。箱が戻りきる前に描き終わるので、弾みとチェックが一続きに見えます。線は DrawSVGPlugin で 0% から 100% まで描くので、線端が丸くても、描き始める前に点が残りません。

塗りは、緑を透明にした色から緑へ補間します。transparent から塗ると、黒の透明から補間することになり、途中の色が黒ずみます。

チェックの線は、塗りより明るい白にします。塗りと同じくらい暗い線だと、描くほど目立たなくなります。外れているときの枠は補足の灰色にします。罫線の色では、箱が地に溶けます。

本物の input は見えなくして label で包み、change で再生と逆再生を切り替えます。箱と文言のどちらを押しても、スペースキーでも切り替わり、フォームの送信もそのまま使えます。フォームの同意、ログイン状態の保持、ToDo リスト、絞り込みの選択に向いています。

コード

HTML
<!-- 本物の input を label で包む。箱と文言のどちらを押してもよく、キーボードとフォームの送信もそのまま使える -->
<label class="check">
  <input class="check__input" type="checkbox" name="remember" />
  <!-- 見た目の箱は飾りなので読み上げから外す。状態は input が持つ -->
  <span class="check__box" aria-hidden="true">
    <svg class="check__svg" viewBox="0 0 24 24" focusable="false">
      <path class="check__mark" d="M6 12.6 L10.4 17 L18.4 8.2" />
    </svg>
  </span>
  <span class="check__label">ログイン状態を保持する</span>
</label>

CSS
.check {
  --size: 22px;     /* 箱の大きさ */
  --edge: #898989;  /* 外れているときの枠(罫線の色だと、箱が地に溶ける) */
  --on: #4f8a64;    /* 付いているときの塗りと枠(成功の色) */
  --mark: #ffffff;  /* チェックの線。塗りより明るくする */
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
}

/* 本物の input は見えなくするだけ(display: none にすると、キーボードで選べなくなる) */
.check__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.check__box {
  position: relative;
  flex: none;
  width: var(--size);
  height: var(--size);
  box-sizing: border-box;
  border: 2px solid var(--edge);
  border-radius: 5px;
}

.check__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* 24 グリッドで線幅 3.2、線端と角は丸。描く準備ができるまで隠しておく(JS が見せる) */
.check__mark {
  fill: none;
  stroke: var(--mark);
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  visibility: hidden;
}

/* キーボードで選んだときは、箱の外に輪を出す */
.check__input:focus-visible + .check__box {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

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

gsap.registerPlugin(DrawSVGPlugin);

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

document.querySelectorAll(".check").forEach((label) => {
  const input = label.querySelector(".check__input");
  const box = label.querySelector(".check__box");
  const mark = label.querySelector(".check__mark");
  const styles = getComputedStyle(label);
  // 色は CSS が正。GSAP は var(--name) のままでは補間できないので、値にして渡す
  const edge = styles.getPropertyValue("--edge").trim();
  const on = styles.getPropertyValue("--on").trim();
  // transparent(黒の透明)から塗ると途中が黒ずむので、同じ色の透明から塗る
  const [r, g, b] = gsap.utils.splitColor(on);
  const clear = `rgba(${r}, ${g}, ${b}, 0)`;

  // 縮んで弾む → その間に枠と地を塗る → 線を描く。外すときは同じタイムラインを逆再生する
  const check = gsap
    .timeline({ paused: true })
    .fromTo(box, { scale: 1 }, { scale: 0.86, duration: 0.1, ease: "power2.in" }, 0)
    .fromTo(box, { scale: 0.86 }, { scale: 1, duration: 0.5, ease: "back.out(3)", immediateRender: false }, 0.1)
    .fromTo(box, { backgroundColor: clear, borderColor: edge }, { backgroundColor: on, borderColor: on, duration: 0.15, ease: "none" }, 0.05)
    // 線端が丸くても、0% のときに頭の点が残らない(DrawSVG が破線の位置をずらす)
    .fromTo(mark, { drawSVG: "0%", visibility: "visible" }, { drawSVG: "100%", duration: 0.35, ease: "power2.out" }, 0.18);

  // 動きを減らす設定では、ほぼ一瞬で切り替える
  if (reduceMotion) check.timeScale(20);

  // 最初からチェック済み(入力を戻したときなど)は、動かさずに終わりの状態にする
  if (input.checked) check.progress(1);

  // label で包んであるので、箱と文言のどちらを押しても、スペースキーでも change が起きる
  input.addEventListener("change", () => (input.checked ? check.play() : check.reverse()));
});

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

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