No.147
TEXT CSSJS

Morphing Text

表示中の単語がとろけるように崩れ、そのまま次の単語へ形を変えるモーフィングテキスト。ぼかしとSVGのしきい値フィルターを組み合わせ、ライブラリなしで作れます。

DEMO

Design, Motion, Code, Ship

CODE

HTML
<div class="demo-stage mph-stage">
  <svg class="mph-defs" aria-hidden="true" focusable="false"><defs><filter id="mph-threshold"><feColorMatrix in="SourceGraphic" type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 255 -140"/></filter></defs></svg>
  <span class="mph-sr">Design, Motion, Code, Ship</span>
  <div class="mph-box" id="mph-box" aria-hidden="true">
    <span class="mph-word" id="mph-a"></span>
    <span class="mph-word" id="mph-b"></span>
  </div>
</div>
CSS
.mph-stage { display:flex; align-items:center; justify-content:center; padding:2rem; background:#0B0B10; min-height:280px; }
.mph-defs { position:absolute; width:0; height:0; }
.mph-sr { position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.mph-box { position:relative; width:100%; max-width:420px; height:90px; filter:url(#mph-threshold) blur(.6px); }
.mph-word { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-family:'Oswald',sans-serif; font-size:3.4rem; font-weight:600; letter-spacing:.04em; color:#fff; }
@media (prefers-reduced-motion: reduce) {
  .mph-box { filter:none; }
}
JS
(function(){
  var a = document.getElementById('mph-a');
  var b = document.getElementById('mph-b');
  if (!a || !b) return;
  var WORDS = ['Design', 'Motion', 'Code', 'Ship'];
  var MORPH = 1.0, HOLD = 1.4;
  var idx = 0, t = 0, last = performance.now(), cool = HOLD;
  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  function show(f){
    b.style.filter = 'blur(' + Math.min(8 / f - 8, 100) + 'px)';
    b.style.opacity = Math.pow(f, 0.4) * 100 + '%';
    var g = 1 - f;
    a.style.filter = 'blur(' + Math.min(8 / g - 8, 100) + 'px)';
    a.style.opacity = Math.pow(g, 0.4) * 100 + '%';
  }
  function set(){ a.textContent = WORDS[idx % WORDS.length]; b.textContent = WORDS[(idx + 1) % WORDS.length]; }
  set();
  if (reduce) {
    b.style.opacity = '0';
    setInterval(function(){ idx++; set(); }, 2400);
    return;
  }
  function frame(now){
    var dt = (now - last) / 1000; last = now;
    if (cool > 0) {
      cool -= dt;
      a.style.filter = ''; a.style.opacity = '100%'; b.style.filter = ''; b.style.opacity = '0%';
    } else {
      t += dt;
      var f = Math.min(t / MORPH, 1);
      show(Math.max(f, 0.0001));
      if (f >= 1) { idx++; t = 0; cool = HOLD; set(); }
    }
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);
})();

AI PROMPT

Claude Code Cursor v0
PROMPT
表示中の単語がとろけるように崩れ、次の単語へ形を変えるモーフィングテキストを作って。同じ位置に2つの span(現在の単語 a と次の単語 b)を重ね、進行度 f(0→1)に応じて b は blur(8/f - 8 px) と opacity f^0.4、a は同じ式を 1-f で適用する(blur は100pxで頭打ち)。親要素に SVG の feColorMatrix フィルターをかけ、アルファ行を「0 0 0 255 -140」にすると、半透明のにじみが0か1に振り分けられて輪郭がくっつき、液体が変形するような見た目になる。1回の変形は1秒、変形後は1.4秒止めてから次へ進む。requestAnimationFrame で経過時間から進行度を計算すること(フレームレートが違っても速さが変わらない)。読み上げ用に全単語を並べた文を視覚的に隠した span に置き、変形する側の入れ物は aria-hidden="true" にする。prefers-reduced-motion: reduce の時はフィルターを外し、2.4秒ごとに単語を切り替えるだけにする。

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

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

BOOKS · PR · AMAZON

📖 なかしまぁ先生のCSSアニメーション入門 📖 UIデザインの教科書 新版 マルチデバイス時代のインターフェース設計 📖 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
→ ROTATING WORDS → SCRAMBLE TEXT → TEXT GENERATE EFFECT

Morphing Text(モーフィングテキスト)とは

ある単語が崩れながら、別の単語の形へ連続的に変わっていく文字の演出です。Magic UI の同名コンポーネントで知られ、ヒーローのキャッチコピーで「〇〇を、もっと速く」の〇〇部分を入れ替える使い方が定番です。

当サイトの Rotating Words は単語を上下にスライドして入れ替える演出、Scramble Text は文字をランダムに乱してから確定させる演出です。本ページは2つの単語の形そのものが溶け合う別テーマで、切り替わりの瞬間に視線を集めたい場面に向きます。

仕組みの中心は、ぼかしで作ったにじみをSVGフィルターで二値化することです。フィルターは描画の負荷が高めなので、1ページに1か所、短い単語に絞って使うと、スマホでも滑らかに動きます。

よくある質問

feColorMatrix のしきい値は何をしているのですか?

アルファ(不透明度)の行を「0 0 0 255 -140」にすると、各画素の不透明度に255を掛けて140を引く計算になります。ぼかしで半透明になったにじみ部分が、ある濃さ以上は完全に不透明、それ未満は完全に透明へ振り分けられるため、2つの単語のにじみがくっついて液体のようにつながって見えます。

setInterval ではなく requestAnimationFrame を使う理由は?

requestAnimationFrame は画面の描き替えに合わせて呼ばれるため、ぼかしの変化が滑らかになり、タブが裏にある間は止まって電力を使いません。経過時間から進行度を計算しているので、60Hz と120Hz の画面で速さが変わることもありません。

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

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