No.165
CURSOR CSSJS

Following Pointer

カードの上にマウスを乗せると、標準のカーソルの代わりに名前ラベル付きの矢印が現れて追いかける演出。共同編集ツールで他の人のカーソルが見える表示に近い見た目です。

DEMO

DESIGN NOTES

動きのあるUIを設計するための5つの原則

Kappy · 6分で読めます

CODE

HTML
<div class="demo-stage fpt-stage">
  <article class="fpt-card" id="fpt-card">
    <div class="fpt-thumb" aria-hidden="true"></div>
    <p class="fpt-tag">DESIGN NOTES</p>
    <h3 class="fpt-title">動きのあるUIを設計するための5つの原則</h3>
    <p class="fpt-meta">Kappy · 6分で読めます</p>
    <div class="fpt-pointer" id="fpt-pointer" aria-hidden="true">
      <div class="fpt-inner">
        <svg viewBox="0 0 24 24" width="20" height="20"><path d="M3 2l17 7-7 2.5L10 19z" fill="currentColor" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg>
        <span class="fpt-name">Kappy</span>
      </div>
    </div>
  </article>
</div>
CSS
.fpt-stage { display:flex; align-items:center; justify-content:center; padding:1.5rem; background:#0B0B10; min-height:320px; }
.fpt-card { position:relative; width:100%; max-width:320px; padding:1rem; border-radius:16px; background:#15151B; border:1px solid rgba(255,255,255,.1); overflow:hidden; }
.fpt-thumb { aspect-ratio:16/9; border-radius:10px; margin-bottom:.9rem; background:linear-gradient(135deg,#7B37A8,#E91B89 55%,#F9CB28); }
.fpt-tag { margin:0 0 .3rem; font-family:'Oswald',sans-serif; font-size:.7rem; letter-spacing:.18em; color:#F472B6; }
.fpt-title { margin:0 0 .5rem; color:#fff; font-size:1rem; line-height:1.5; }
.fpt-meta { margin:0; color:#A1A1AA; font-size:.74rem; }
.fpt-pointer { position:absolute; top:0; left:0; pointer-events:none; will-change:transform; }
.fpt-inner { --fpt-c:#D1177A; display:flex; align-items:flex-start; color:var(--fpt-c); transform:scale(0); transform-origin:0 0; opacity:0; transition: transform .2s cubic-bezier(.34,1.56,.64,1), opacity .2s ease; }
.fpt-inner svg { display:block; filter: drop-shadow(0 2px 4px rgba(0,0,0,.4)); }
.fpt-name { margin:14px 0 0 -2px; padding:.2rem .6rem; border-radius:999px; background:var(--fpt-c); color:#fff; font-size:.72rem; font-weight:600; white-space:nowrap; }
.fpt-card.is-active .fpt-inner { transform:scale(1); opacity:1; }
@media (hover: hover) and (pointer: fine) {
  .fpt-card.is-active { cursor:none; }
}
@media (prefers-reduced-motion: reduce) {
  .fpt-inner { transition-duration:.01ms; }
}
JS
(function(){
  var card = document.getElementById('fpt-card');
  var ptr = document.getElementById('fpt-pointer');
  if (!card || !ptr) return;
  var inner = ptr.firstElementChild;
  var COLORS = ['#D1177A', '#7B37A8', '#0369A1', '#047857'];
  function move(e){
    var r = card.getBoundingClientRect();
    ptr.style.transform = 'translate(' + (e.clientX - r.left) + 'px,' + (e.clientY - r.top) + 'px)';
  }
  function show(e){
    if (e.pointerType !== 'mouse') return;
    if (!card.classList.contains('is-active')) inner.style.setProperty('--fpt-c', COLORS[Math.floor(Math.random() * COLORS.length)]);
    move(e);
    card.classList.add('is-active');
  }
  card.addEventListener('pointerenter', show);
  card.addEventListener('pointermove', show);
  card.addEventListener('pointerleave', function(){ card.classList.remove('is-active'); });
  window.addEventListener('scroll', function(){ card.classList.remove('is-active'); }, { passive: true });
})();

AI PROMPT

Claude Code Cursor v0
PROMPT
カードの上にマウスを乗せると、標準のカーソルの代わりに名前ラベル付きの矢印が現れて追いかける Following Pointer を作って。カードに position:relative と overflow:hidden を付け、その中に aria-hidden="true"・pointer-events:none の要素を position:absolute(top:0; left:0)で置き、pointermove のたびに transform: translate(カード内のX, カード内のY) で動かす(top/left を毎回書き換えない)。中身は左上を指す矢印の SVG(fill: currentColor)と、その右下に置く丸いラベル(名前)で、色はカスタムプロパティ --fpt-c で矢印とラベルの背景に共通で使う。表示し直すたび(pointerenter、またはスクロールで隠れた後に動かした時)に色を4色からランダムに選ぶ(白い文字とのコントラストが4.5:1以上ある濃い色だけにする)。現れる時は transform-origin: 0 0 で scale(0) から scale(1) へ cubic-bezier(.34,1.56,.64,1) で弾むように、pointerleave で縮んで消える。pointerType が mouse の時だけ動かし、@media (hover: hover) and (pointer: fine) の時だけカード内の標準カーソルを cursor:none で隠す。ページがスクロールされたらポインターを隠し(カードが動くと本当の位置とずれるため)、次にマウスを動かした時にその位置から出し直す。@media (prefers-reduced-motion: reduce) では拡大の動きを無効化する。

Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift

AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する

BOOKS · PR · AMAZON

📖 なかしまぁ先生のCSSアニメーション入門 📖 マイクロインタラクション ―UI/UXデザインの神が宿る細部 📖 Fundamentals of Web Animation with GSAP

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

学びを止めない · AMAZONサブスク

📚 Kindle Unlimited — 技術書・デザイン書が読み放題。30日無料体験 → 🎧 Audible — 移動中に耳で学ぶオーディオブック。30日無料体験 → 📦 Amazon Prime — Prime Reading・配送特典つき。30日無料体験 → 🎵 Music Unlimited — 作業用BGMに。1億曲が聴き放題・30日無料体験 →

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

RELATED EFFECTS

↗ MORE
→ CURSOR GLOW FOLLOW → CUSTOM CURSOR → TOOLTIP

Following Pointer(ラベル付きの追従ポインター)とは

特定のカードや領域の上にマウスを乗せた時だけ、標準のカーソルの代わりに名前ラベル付きの矢印を表示して追いかけさせる演出です。Aceternity UI にも同じ名前のコンポーネント(Following Pointer)があり、公式の説明では「マウスの矢印に追従し、ポインターと中身がアニメーションで現れるカスタムポインター」とされています。

当サイトの Custom Cursor はページ全体のカーソルを置き換える基本形、Cursor Glow Follow は光がカーソルを追いかける演出、Tooltip は要素に補足を出す部品です。本ページは領域を限って、矢印とラベルを組にして見せる別テーマで、共同編集ツールで他の人のカーソルが見える表示に近い見た目になります。

ポインターはあくまで装飾なので、押せる要素の邪魔をしないことが大前提です。pointer-events:none と aria-hidden を付け、タッチ端末では表示しない作りにしておくと、使い勝手を損なわずに取り入れられます。

よくある質問

位置を top と left ではなく transform で動かすのはなぜですか?

top や left を書き換えると、ブラウザはそのたびにレイアウトを計算し直します。transform の translate は描画の段階だけで位置を変えるため、マウスの動きに合わせて毎回更新しても軽く動きます。ポインターの要素は pointer-events:none にして、下にあるリンクやボタンのクリックを邪魔しないようにしています。

ラベルの色をランダムにする時の注意点は?

白い文字を載せるなら、どの色でも文字とのコントラスト比が4.5:1以上になる色だけを候補にします。明るい水色や黄色は白い文字が読みにくくなるため、本実装では濃いピンク(#D1177A・約5.1:1)・紫・青・緑の4色に絞っています。サイトのアクセント色がそのままでは基準に届かない場合は、ラベルの背景だけ少し濃くしてください。共同編集ツールのように人ごとに色を分ける場合も、同じ基準で色を選んでください。

コードは無料で使えますか?

はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。