No.128
MICRO CSSJS

Animated List

新着アイテムが上から差し込まれ、既存の行が下へ押し出されていく通知リスト。CSS Grid の行アニメーションと組み合わせ、行の増減を滑らかに見せる実装。

DEMO

CODE

HTML
<div class="demo-stage anl-stage">
  <div class="anl-list" id="anl-list" aria-live="polite"></div>
</div>
CSS
.anl-stage { display:flex; align-items:center; justify-content:center; padding:2rem; background:#0B0B10; min-height:280px; overflow:hidden; }
.anl-list { display:flex; flex-direction:column; gap:.7rem; width:100%; max-width:360px; }
.anl-item {
  display:flex; align-items:center; gap:.9rem;
  padding:.85rem 1rem; border-radius:12px;
  background:#17171C; border:1px solid rgba(255,255,255,.08);
  animation: anl-in .5s cubic-bezier(.22,1,.36,1) both;
}
.anl-icon {
  flex:0 0 32px; width:32px; height:32px; border-radius:9px;
  display:flex; align-items:center; justify-content:center; font-size:.95rem;
}
.anl-body { min-width:0; }
.anl-title { font-family:'Inter',sans-serif; font-size:.8rem; color:#EDEDED; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.anl-meta { font-family:'JetBrains Mono',monospace; font-size:.65rem; color:#6E6E7A; margin-top:.15rem; }
@keyframes anl-in {
  from { opacity:0; transform:translateY(-14px) scale(.94); }
  to   { opacity:1; transform:translateY(0) scale(1); }
}
.anl-item.anl-out { animation: anl-out .4s ease forwards; }
@keyframes anl-out {
  to { opacity:0; transform:scale(.94); margin-bottom:-3.2rem; }
}
@media (prefers-reduced-motion: reduce) {
  .anl-item { animation-duration:.01ms; }
  .anl-item.anl-out { animation-duration:.01ms; }
}
JS
(function(){
  var list = document.getElementById('anl-list');
  if (!list) return;
  var DATA = [
    { icon: '💸', bg: 'rgba(233,27,137,.16)', title: 'Payment received', meta: '$1,240.00' },
    { icon: '👤', bg: 'rgba(91,170,222,.16)', title: 'New user signed up', meta: 'from Osaka, JP' },
    { icon: '🚀', bg: 'rgba(123,55,168,.16)', title: 'Deploy succeeded', meta: 'build #1284' },
    { icon: '⭐', bg: 'rgba(255,193,7,.16)', title: 'Repository starred', meta: '+18 today' },
    { icon: '💬', bg: 'rgba(16,185,129,.16)', title: 'New message', meta: 'support inbox' }
  ];
  var MAX = 4;
  var i = 0;
  function push(){
    var d = DATA[i % DATA.length];
    i++;
    var el = document.createElement('div');
    el.className = 'anl-item';
    el.innerHTML = '<span class="anl-icon" style="background:' + d.bg + '">' + d.icon + '</span>' +
                   '<span class="anl-body"><span class="anl-title">' + d.title + '</span>' +
                   '<span class="anl-meta">' + d.meta + '</span></span>';
    list.prepend(el);
    while (list.children.length > MAX) {
      var last = list.lastElementChild;
      if (last.classList.contains('anl-out')) break;
      last.classList.add('anl-out');
      (function(node){ setTimeout(function(){ if (node.parentNode) node.parentNode.removeChild(node); }, 400); })(last);
    }
  }
  push(); push(); push();
  setInterval(push, 2200);
})();

AI PROMPT

Claude Code Cursor v0
PROMPT
新着アイテムが上から差し込まれ、古い行が下から抜けていく通知リストを作って。JSは要素を prepend するだけにし、動きはCSSに任せる。追加側は @keyframes で opacity: 0; transform: translateY(-14px) scale(.94) から opacity: 1; transform: none へ、animation-fill-mode: both。削除側は削除用クラスを付けて opacity: 0; transform: scale(.94); margin-bottom: 負の値(=行の高さぶん)へアニメーションさせ、アニメーション時間ぶん待ってから removeChild する。負の margin を使うのは、高さが縮む過程を再現して下の行が滑らかに詰まるようにするため。表示上限(例4件)を決め、超えたぶんから順に退場させる。要点: 追加のたびに全行を再描画すると重いので、既存要素には触らず新規要素だけを挿入する。読み上げ対応として親に aria-live="polite" を付ける。

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
→ TOAST NOTIFICATION → STACKED CARDS → BADGE BOUNCE

Animated List(積み上がる通知リスト)とは

新着が上から差し込まれ、古い行が下から抜けていく通知リストの演出です。Magic UI の Animated List として知られ、SaaSのランディングページで「リアルタイムに動いているプロダクト」を示す装飾としてよく使われます。

当サイトの Toast Notification は単発の通知が一時的に現れて消える表現で、実際の操作フィードバックに使うものです。本ページは複数件が継続的に流れ続ける「状態のショーケース」という別テーマで、実データの表示にも装飾にも転用できます。

実装の勘所は退場処理です。要素を即座に削除すると下の行が飛ぶため、負の margin で高さの縮小を見せてから DOM を取り除きます。

よくある質問

行が詰まるときにガタつきます。どう直しますか?

退場する要素を即座に削除すると、下の行が瞬間的に上へ飛びます。削除用クラスで margin-bottom を行の高さぶんマイナスへアニメーションさせ、その完了を待ってから DOM から取り除くと、高さが縮む過程が見えて滑らかに詰まります。本ページのコードはこの方式です。

リストの上限は何件が適切ですか?

常時流れる通知の演出なら3〜5件が見やすい範囲です。上限を大きくすると、画面内で同時にアニメーションする要素が増えて負荷が上がるうえ、視線がどこを追えばよいか分からなくなります。履歴を全件見せたい場合は別ページに逃がし、この演出は「最新数件」に限定するのが定石です。

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

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