第203章:マウントアニメーション(フワッと表示)✨🪽
この章では「コンポーネントが**画面に現れた瞬間(=マウント)**に、フワッと気持ちよく登場させる」方法をやるよ〜!😊💕
1) 今日のゴール🎯✨
motion.divを使って、登場アニメーションを付けられるようになる🙌initial/animate/transitionの意味がわかる🧠💡variantsで、アニメ設定をスッキリまとめられる📦✨
2) 準備:Framer Motion(Motion)を入れる🧰✨
ViteのReactプロジェクトで、ターミナルを開いて👇
npm i framer-motion
※ npm上の framer-motion は今も更新が続いていて、最新は 12.x 系だよ(2025年12月時点)🆕✨ (npmjs.com)
3) まずは最小:カードが「フワッ」と出る🪄✨
src/App.tsx をこうしてみてね👇(まずはコピペでOK!)
import { motion } from "framer-motion";
export default function App() {
return (
<div style={{ padding: 24 }}>
<motion.div
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.35, ease: "easeOut" }}
style={{
padding: 16,
borderRadius: 12,
background: "white",
boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
maxWidth: 420,
}}
>
<h1 style={{ margin: 0, fontSize: 20 }}>ようこそ〜!🎉</h1>
<p style={{ marginTop: 8, marginBottom: 0 }}>
画面に出てきた瞬間にフワッと表示されるよ 😊✨
</p>
</motion.div>
</div>
);
}
ここが超大事ポイント💡👀
initial: 最初の見た目(透明+少し下)animate: 最終の見た目(不透明+定位置)transition: 動き方(何秒で、どんな加速で)
4) マウントアニメーションの流れ(図解)🗺️✨
「描画された直後に initial が適用されて、そこから animate に移動する」って感じだよ〜!🥰
5) ちょい応用:variantsで“読みやすく”する📦✨
同じアニメを他の場所でも使いたい時、variants が便利〜!🎀
import { motion, type Variants } from "framer-motion";
const cardVariants: Variants = {
hidden: { opacity: 0, y: 12, scale: 0.98 },
show: { opacity: 1, y: 0, scale: 1 },
};
export default function App() {
return (
<div style={{ padding: 24 }}>
<motion.div
variants={cardVariants}
initial="hidden"
animate="show"
transition={{ duration: 0.35, ease: "easeOut" }}
style={{
padding: 16,
borderRadius: 12,
background: "white",
boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
maxWidth: 420,
}}
>
<h1 style={{ margin: 0, fontSize: 20 }}>variants版だよ〜✨</h1>
<p style={{ marginTop: 8, marginBottom: 0 }}>
アニメの設定がスッキリして気持ちいい😊🫶
</p>
</motion.div>
</div>
);
}
6) “追加した瞬間”にフワッ(リストで体験)🧁✨
「ボタンで項目を追加」→「追加された項目がマウント」→「フワッ!」ってなるやつ!😆🎉
import { useState } from "react";
import { motion } from "framer-motion";
type Item = { id: string; text: string };
export default function App() {
const [items, setItems] = useState<Item[]>([
{ id: crypto.randomUUID(), text: "最初のカードだよ🍓" },
]);
const addItem = () => {
const next: Item = { id: crypto.randomUUID(), text: "追加されたよ〜🎈" };
setItems((prev) => [next, ...prev]);
};
return (
<div style={{ padding: 24, maxWidth: 520 }}>
<button
onClick={addItem}
style={{
padding: "10px 14px",
borderRadius: 10,
border: "1px solid #ddd",
background: "white",
cursor: "pointer",
}}
>
+ 追加する✨
</button>
<div style={{ marginTop: 16, display: "grid", gap: 12 }}>
{items.map((item) => (
<motion.div
key={item.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.28, ease: "easeOut" }}
style={{
padding: 14,
borderRadius: 12,
background: "white",
boxShadow: "0 8px 24px rgba(0,0,0,0.10)",
}}
>
{item.text}
</motion.div>
))}
</div>
</div>
);
}
ここでは「登場(マウント)」だけをやってるよ💡 「消えるとき(アンマウント)」にもアニメしたい場合は、次の 第204章:AnimatePresence の出番!👻✨
7) よくあるハマりどころ😵💫💦
-
keyが同じだと、追加しても同じ要素扱いになって、期待どおり動かないことがあるよ🗝️ → リストの各要素は ユニークなkeyにしよう✨ -
“最初から表示されてるもの”に毎回アニメが走ってほしくないこともある →
initial={false}みたいな制御もできるよ(SSR等の話も絡む)📌 (motion.dev)
8) 練習ミッション💪🎀
ミッションA:上から“ふわっ”と通知を出す📣✨
initial={{ opacity: 0, y: -12 }}animate={{ opacity: 1, y: 0 }}transition={{ duration: 0.25, ease: "easeOut" }}
ミッションB:気持ちいいバネにする🪀✨
transition={{ type: "spring", stiffness: 420, damping: 28 }}(バネは数字で感覚を掴むのがコツだよ〜!🥰)
次は 第204章:AnimatePresence(消える時もアニメ) に行くと、UIが一気に“プロっぽく”なるよ〜!🎓✨