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

フォーム

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

デモ

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

仕様

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

しくみと調整

押した四角が一瞬すぼまってから弾むように戻る、そのわずかなあいだに背景が緑で塗られ、白いチェックの線が描かれていきます。外すときは同じタイムラインを逆再生するので、線が巻き戻るように消えてから、背景の色が抜けます。

縮むのは0.86倍まで、戻りは0.5秒の back.out(3)。塗りは縮み始めてすぐに切り替わり、チェックの線は少し遅れて描き始め、四角が戻りきる前に描き終えるようにしました。弾みと線が重なるので、ひと続きの動作に見えます。線は DrawSVGPlugin で描いていて、線端を丸くしていても、描き始める前に丸い点だけが残ることはありません。

背景の塗りは、緑を透明にした色から緑へ補間しています。transparent から塗れば済みそうですが、CSS の transparent は黒を透明にした色として扱われるので、補間の途中で色が黒ずみます。線の色も、塗りより明るい白にしてあります。塗りと同じくらい暗い色の線だと、描くほど緑に埋もれていくからです。外れているときの枠線はグレーで、罫線と同じ淡い色では四角が背景に溶けます。

本物の input は見えなくして label で包み、change イベントでタイムラインの再生と逆再生を切り替えています。四角でも文言でも、スペースキーでも切り替わり、フォームの送信もふつうのチェックボックスのまま使えます。

コード

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 サイト制作、端末ごとの見え方や表示速度の考え方はレスポンシブウェブサイトのページにまとめています。映像として作る動きをお探しの場合はモーショングラフィックスをご覧ください。