フレーマーモーションの紹介
公開: 2022-03-10この記事では、FramerMotionがすばらしいアニメーションの作成にどのように役立つかを詳しく見ていきます。 モーションコンポーネントがどのように機能するかを学び、アニメーションを連鎖させる方法を学びます。 フレーマモーションを使用して、ジェスチャでトリガーされ、タイミングを合わせてスクロールするアニメーションを作成する方法について説明します。 その過程で、私が設定した5つのデモアプリケーションを構築するために学んだことを使用して、FramerMotionを実際のアプリケーションに統合する方法を示します。
このチュートリアルは、Reactアプリケーションにアニメーションを統合することに関心のある読者にとって有益です。
注:この記事では、ReactとCSSの基本的な理解が必要です。
フレーマーモーションとは何ですか?
Framer Motionは、アニメーションの作成を簡単にするアニメーションライブラリです。 その簡素化されたAPIは、アニメーションの背後にある複雑さを抽象化し、アニメーションを簡単に作成できるようにします。
モーションコンポーネント
これらは、フレーマーモーションの構成要素です。 モーションコンポーネントは、通常のHTMLおよびSVG要素(例: motion.h1
)の前にmotion
を付けることで作成されます。 モーションコンポーネントは複数のプロップを受け入れることができ、基本的なものはanimate
プロップです。 このプロップは、アニメートするコンポーネントのプロパティを定義するオブジェクトを取り込みます。 定義するプロパティは、コンポーネントがDOMにマウントされるときにアニメーション化されます。
FramerMotionを使用してh1テキストをアニメートしましょう。 まず、framer-motionライブラリをインストールし、 motion
をインポートします。
npm i framer-motion import { motion } from 'framer-motion';
次に、h1をモーションコンポーネントに変換します。
<motion.h1 animate={{x: 20, y: -20}}> This is a motion component </motion.h1>
これにより、 h1
が右に20ピクセルスライドし、ロード時に20ピクセル上に移動します。 単位が追加されていない場合、計算はピクセルを使用して行われます。 ただし、計算の基にする単位を明示的に設定できますanimate={{x: "20rem", y: "-20rem"}}>
。
デフォルトでは、モーションコンポーネントは、そのスタイルから定義された状態からanimate
プロップの状態にアニメートされます。 ただし、必要に応じて、 initial
プロップを使用して、コンポーネントの初期アニメーション状態をハイジャックして定義することができます。 animate
プロップは、コンポーネントがマウントされるときのコンポーネントの動作を定義するために使用されますが、 initial
プロップは、コンポーネントがマウントされる前の動作を定義します。
h1を左から入れたい場合は、最初の小道具を使用してそれを制御します。
<motion.h1 initial={{x: -1000}} animate={{x: 20}}> This is a motion component </motion.h1>
これで、 h1
がマウントされると、左からスライドインします。
単一のアニメーションに限定されません。 keyframes
と呼ばれる一連のアニメーションを値の配列で定義できます。 各値は順番にアニメーション化されます。
<motion.h1 initial={{x: -1000}} animate={{x: [20, 50, 0, -70, 40] }}> This is a motion component </motion.h1>
transition
プロップを使用すると、アニメーションの発生方法を定義できます。 これを使用して、値が1つの状態から別の状態にアニメーション化する方法を定義します。 特に、このプロップを使用して、アニメーションのduration
、 delay
、およびtype
を定義できます。
<motion.h1 initial={{ x: -1000 }} animate={{ x: 0 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion component </motion.h1>
以下のコードスニペットのように、複数のモーションコンポーネントを同時にアニメーション化するとします。
<div className="App"> <motion.h1 initial={{ x: -1000 }} animate={{ x: 0 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion h1 </motion.h1> <motion.h2 initial={{ y: -1000 }} animate={{ y: 0 }} transition={{ type: "tween", duration: "1", delay: ".4" }}>This is a motion h2 </motion.h2> <motion.h3 initial={{ x: 100, opacity: 0 }} animate={{ x: 0, opacity: 1 }}> This is a motion h3 </motion.h3> <motion.h4 initial={{ scale: 0.7 }} animate={{ scale: 1.7 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion h4 </motion.h4> </div>
これは機能しますが、Framer Motionのvariants
プロップを使用すると、アニメーション定義をバリアントオブジェクトに抽出できます。 variants
を使用すると、コードがすっきりするだけでなく、さらに強力で複雑なアニメーションを作成できます。
アニメーション定義をバリアントオブジェクトに抽出すると、次のようになります。
const H1Variants = { initial: { x: -1000 }, animate: { x: 0 }, transition: { type: "tween", duration: 2, delay: 1 } } const H2Variants = { initial: { y: -1000 }, animate: { y: 0 }, transition: { type: "tween", duration: 1, delay: .4 } } const H3Variants = { initial:{ x: 100, opacity: 0 }, animate:{ x: 0, opacity: 1 } } const H4Variants = { initial:{ scale: 0.7 }, animate:{ scale: 1.7 }, transition:{ type: "tween", duration: "2", delay: "1" } }
アニメーション定義をコンポーネントのinitial
プロップとanimate
プロップに直接渡す代わりに、これらの定義をスタンドアロンのバリアントオブジェクトに抽出します。 バリアントオブジェクトでは、各アニメーションの名前をバリアントとして説明するバリアント名を定義します。
<div className="App"> <motion.h1 variants={H1Variants} initial='initial' animate='animate' > This is a motion h1 </motion.h1> <motion.h2 variants={H2Variants} initial='initial' animate='animate' > This is a motion h2 </motion.h2> <motion.h3 variants={H3Variants} initial='initial' animate='animate' > This is a motion h3 </motion.h3> <motion.h4 variants={H4Variants} initial='initial' animate='animate' > This is a motion h4 </motion.h4> </div>
variants
プロップでは、各モーションコンポーネントのバリアントオブジェクトの名前を渡してから、アニメーションをinitial
プロップとanimate
プロップに渡します。
繰り返しを減らすために、バリアントを使用して現在の設定をさらに進めることができます。 バリアントを使用すると、親モーションコンポーネントからDOMを介してアニメーション属性を伝播できます。 これを機能させるために、親のmotion.div
のバリアントを作成し、そのバリアントオブジェクトに子と同様のアニメーション名を付けます。 これにより、各子コンポーネントにアニメーション名を渡す必要がなくなります。 舞台裏では、親要素がそれを処理します。
const ContainerVariants = { initial: {}, animate: {} }; const H1Variants = { initial: { x: -1000 }, animate: { x: 0 }, transition: { type: "tween", duration: 2, delay: 1 } }; //more variants below <motion.div className="App" variants={ContainerVariants} initial="initial" animate="animate" > <motion.h1 variants={H1Variants}>This is a motion h1</motion.h1> <motion.h2 variants={H2Variants}>This is a motion h2</motion.h2> <motion.h3 variants={H3Variants}>This is a motion h3</motion.h3> <motion.h4 variants={H4Variants}>This is a motion h4</motion.h4> </motion.div>
これで、繰り返しのない、よりクリーンなコードができました。 コンテナdivをモーションコンポーネントに変えて、定義したContainerVariants
オブジェクトを渡すことができるようにしました。 コンテナにアニメーションを定義しないため、空のオブジェクトをinitial
化してanimate
ます。 伝播が機能するには、アニメーション名がすべてのバリアントオブジェクトで同じである必要があります。
これで、フレーマーモーションの基本を理解できました。 5つのデモアプリケーションの最初の作成を始めましょう。
アイコンショップ
ジェスチャーに基づいたインタラクティブなアニメーションを作成できます。 モーションコンポーネントは現在、ホバー、タップ、パン、およびドラッグジェスチャ検出をリッスンできます。 whileHover
プロップを使用してこのアイコンショップアプリを構築します。
コンポーネント
App.js
:これは見出しテキストを保持します。-
Card.jsx
:ここでは、アイコンカードのアニメーションを定義します。 -
CardContainer.jsx
:アイコンをインポートしてループします。 -
styles.js
:モーションコンポーネントを作成、スタイル設定、およびエクスポートします。 コンポーネントのスタイリングには、styled-componentsを使用しました。
App.js
から始めましょう。
import { H1, H2 } from "./Styles"; import CardContainer from "./CardContainer"; return ( <div> <H1 initial={{ y: -100 }} animate={{ y: 0, transition: { delay: 1 } }}> Icon Shop </H1> <H2 initial={{ x: -1000 }} animate={{ x: 0, transition: { delay: 1 } }}> Hover over the cards to see the motion magic </H2> <CardContainer /> </div> );
Styles.js
ファイルで作成したH1
およびH2
モーションコンポーネントをインポートします。 これらはモーションコンポーネントであるため、 initial
プロップとanimate
プロップを使用して、マウントする前とマウントするときの動作を定義します。 ここでは、 CardContiner
コンポーネントもインポートして表示します。
さて、 CardContainer.js
。
import { Container } from "./Styles"; import Card from "./Card"; import { ReactComponent as AddIcon } from "./assets/add.svg"; import { ReactComponent as AirplaneIcon } from "./assets/airplane.svg"; import { ReactComponent as AlarmIcon } from "./assets/alarm.svg"; //more svg imports below... const icons = [ <AddIcon />, <AirplaneIcon />, <AlarmIcon />, //more icons below ]; const CardContainer = () => { return ( <Container initial={{ x: -1000 }} animate={{ x: 0 }}> {icons.map((icon) => ( <Card icon={icon} /> ))} </Container> ); };
ここでは、SVG、 Container
モーションコンポーネント、およびCard
コンポーネントをインポートします。
App.js
のH1
とH2
と同様に、 initial
プロップとanimate
プロップを使用してContainer
のアニメーションを定義します。 ロードすると、ブラウザの左側からスライドインするというクールな効果が得られます。
さて、 Card.js
import { CardBox, IconBox } from "./Styles"; const CardVariants = { beforeHover: {}, onHover: { scale: 1.1 } }; const IconVariants = { beforeHover: { opacity: 0, y: -50 }, onHover: { opacity: 1, y: 0, scale: 1.5, transition: { type: "tween" } } }; const Card = ({ icon }) => { console.log(icon); return ( <CardBox variants={CardVariants} initial="beforeHover" whileHover="onHover"> <IconBox variants={IconVariants}>{icon}</IconBox> </CardBox> ); };
ここでは、 onHover
beforeHover
を使用して2つのバリアントオブジェクトを作成します。 CardVariants
オブジェクトでは、最初は何もしたくないので、 beforeHover
は空のオブジェクトです。 onHover
は、カードボックスのスケールを大きくします。

IconVariants
オブジェクトでは、 IconBox
でbeforeHover
の初期状態を定義します。 不透明度を0に設定し、50px上に押し上げます。 次に、 onHover
で、不透明度を1に戻し、デフォルトの位置に押し戻し、トランジションタイプをtween
に変更します。 次に、バリアントをそれぞれのモーションコンポーネントに渡します。 伝播を利用するため、 IconBox
コンポーネントにinitial
およびanimate
の小道具を明示的に設定する必要はありません。
アニメーションナビゲーションバー
単純なナビゲーションコンポーネントを作成し、親と子のモーションコンポーネント間のタイミング関係を作成する方法を確認します。
コンポーネント
App.js
:これは見出しテキストを保持します。-
Styles.js
:モーションコンポーネントを作成、スタイル設定、およびエクスポートします。 コンポーネントは、styled-componentsを使用してスタイル設定されます。
App.js
ファイルを見てみましょう。
import { Header, Nav, Link, SvgBox } from "./Styles"; function App() { const [isOpen, setIsOpen] = useState(false); const iconVariants = { opened: { rotate: 135 }, closed: { rotate: 0 } }; const menuVariants = { opened: { top: 0, transition: { when: "beforeChildren", staggerChildren: 0.5 } }, closed: { top: "-90vh" } }; const linkVariants = { opened: { opacity: 1, y: 50 }, closed: { opacity: 0, y: 0 } };
Navbarが開いているかどうかを確認するために使用されるisOpen
状態を作成します。 3つのバリアントオブジェクト、 iconVariants
、 menuVariants
、およびlinkVariants
を作成し、それぞれSvgBox
、 Nav
、およびLink
モーションコンポーネントのアニメーションを定義します。 iconVariants
は、SvgBoxにカーソルを合わせたときにSvgBox
を135度回転させるために使用されます。 値に「度」を追加する必要はありません。 menuVariants
では、CSSのposition
プロパティを使用するのと同じように、 Nav
の一番上の位置を制御します。 Nav
状態に基づいて、 isOpen
の上部の位置を切り替えます。
バリアントを使用すると、親と子のモーションコンポーネント間にタイミング関係を作成できます。 遷移オブジェクトのwhen
プロパティを使用して、親Nav
とその子Link
の間の関係を定義します。 ここでは、 beforeChildren
に設定して、子のアニメーションが開始する前に親コンポーネントのアニメーションが終了するようにします。
staggerChildren
プロパティを使用して、各リンクのタイミング順序を設定します。 各リンクが次々に表示されるまで0.5秒かかります。 これにより、 Nav
を開いたときに視覚的な手がかりが作成されます。 linkVariants
では、各リンクの不透明度と垂直位置をアニメーション化します。
<div className="App"> <Header> <SvgBox variants={iconVariants} animate={isOpen ? "opened" : "closed"} onClick={() => setIsOpen(!isOpen)} > <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="https://www.w3.org/2000/svg" > <path d="M12 4C11.4477 4 11 4.44772 11 5V11H5C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13H11V19C11 19.5523 11.4477 20 12 20C12.5523 20 13 19.5523 13 19V13H19C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11H13V5C13 4.44772 12.5523 4 12 4Z" fill="#fff" /> </svg> </SvgBox> </Header> <Nav initial={false} variants={menuVariants} animate={isOpen ? "opened" : "closed"} > <Link variants={linkVariants}>home</Link> <Link variants={linkVariants}>about</Link> <Link variants={linkVariants}>gallery</Link> </Nav> </div>
ここでは、バリアントをそれぞれのコンポーネントに渡します。 SvgBox
では、クリックされるたびにisOpen
の状態を切り替え、状態に基づいて条件付きでアニメーション化します。 SvgBox
と同様に、 isOpen
の状態に基づいてNav
とLink
を条件付きでアニメーション化します。
アニメーションモーダル
モーダルコンポーネントを作成し、Framer MotionのAnimatePresence
と、要素がDOMを離れるときに要素をアニメーション化する方法について学習します。
コンポーネント:
-
App.js
:ここでshowModal
状態を設定します。 -
Modal.jsx
:実際のアニメーション作業はここで行われます。 -
Styles.js
:モーションコンポーネントを作成、スタイル設定、およびエクスポートします。 コンポーネントは、styled-componentsを使用してスタイル設定されます。
App.js
を調べてみましょう
import { ToggleButton, Container } from "./Styles"; import Modal from "./Modal"; function App() { const [showModal, setShowModal] = useState(false); const toggleModal = () => { setShowModal(!showModal); }; return ( <Container> <ToggleButton initial={{ x: -700 }} animate={{ x: 0, transition: { duration: 0.5 } }} onClick={toggleModal} > Toggle Modal </ToggleButton> <Modal showModal={showModal} /> </Container> ); }
モーダルを条件付きでレンダリングするために使用されるshowModal
状態を作成します。 toggleModal
関数は、 ToggleButton
がクリックされるたびに状態を切り替えます。 ToggleButton
はモーションコンポーネントであるため、アニメーションを定義できます。 マウントすると左からスライドインします。 このアニメーションは0.5秒間実行されます。 また、小道具を介してshowModal
状態をModal
に渡します。
さて、 Modal.jsx
import { AnimatePresence } from "framer-motion"; import { ModalBox, ModalContent, Container } from "./Styles"; <Container> <AnimatePresence> {showModal && ( <ModalBox initial={{ opacity: 0, y: 60, scale: 0.3 }} animate={{ opacity: 1, y: 0, scale: 1, transition: { type: "spring", stiffness: 300 } }} exit={{ opacity: 0, scale: 0.5, transition: { duration: 0.6 } }} > <ModalContent initial={{ y: -30, opacity: 0 }} animate={{ y: 0, opacity: 1, transition: { delay: 1 } }} > Modal content!!!! </ModalContent> </ModalBox> )} </AnimatePresence> </Container>
framer-motion
からAnimatePresence
をインポートします。 これにより、コンポーネントがDOMを離れるときにコンポーネントの終了アニメーションを設定できます。 showModal
状態に基づいてModal
を条件付きでレンダリングします。 ModalBox
とModalContent
のアニメーションは、 initial
小道具とanimate
の小道具を使用して定義します。 ここには新しい小道具もあります、 exit
。 ラッパーとしてAnimatePresence
を使用すると、 exit
プロップのModalBox
に終了アニメーションを追加できます。
スクロールアニメーション
useAnimation
フックとreact-intersection-observer
の組み合わせを使用して、スクロールトリガーアニメーションを作成します。
コンポーネント
App.js
:Box
コンポーネントのアニメーションを設定し、App
でレンダリングしますStyles.js
:モーションコンポーネントを作成、スタイル設定、およびエクスポートします。 コンポーネントは、styled-componentsを使用してスタイル設定されます。
import React, { useEffect } from "react"; import { useAnimation } from "framer-motion"; import { useInView } from "react-intersection-observer"; import { Container, H1,StyledBox } from "./Styles"; const BoxVariants = { visible: { opacity: 1, x: 0, transition: { duration: 1 } }, hidden: { opacity: 0, x: 300 }, }; const Box = () => { const controls = useAnimation(); const [ref, inView] = useInView(); useEffect(() => { if (inView) { controls.start("visible"); } }, [controls, inView]); return ( <StyledBox ref={ref} animate={controls} initial="hidden" variants={BoxVariants} /> ); };
useAnimation
フックを使用すると、アニメーションが発生するシーケンスを制御できます。 アニメーションを手動で開始および停止するために使用できるcontrols.stop
controls.start
にアクセスできます。 最初のhidden
アニメーションをStyledBox
に渡します。 start
メソッドで定義したコントロールをStyledBox
に渡します。
react-intersection-observer
のuseInView
フックを使用すると、コンポーネントがビューポートに表示されるタイミングを追跡できます。 useInView
フックを使用すると、監視するコンポーネントに渡すref
と、その要素がinView
であるかどうかを通知するinView
ブール値にアクセスできます。 useEffect
を使用して、監視している要素であるStyledBox
が表示されているときはいつでもcontrols.start
を呼び出します。 controls
とinView
をuseEffect
の依存関係として渡します。 また、定義したバリアントBoxVariants
をStyledBox
に渡します。
ヒーローアニメーション
useCycle
フックを使用して、クールなヒーローバナーアニメーションを作成します。 useCycle
を使用してアニメーションを循環させる方法を理解します。
import React, { useEffect } from "react"; import { useCycle } from "framer-motion"; import { Container, H1, HeroSection, Banner, TextBox } from "./Styles"; import { ReactComponent as BannerIllustration } from "./bighead.svg"; const H1Variants = { initial: { y: -200, opacity: 0 }, animate: { y: 0, opacity: 1, transition: { delay: 1 } }, }; const TextVariants = { initial: { x: 400 }, animate: { x: 0, transition: { duration: 0.5 } }, }; const BannerVariants = { animationOne: { x: -250, opacity: 1, transition: { duration: 0.5 } }, animationTwo: { y: [0, -20], opacity: 1, transition: { yoyo: Infinity, ease: "easeIn" }, }, };
H1Variants
、 TextVariants
、 BannerVariants
の3つのバリアントを定義します。 ただし、私たちの焦点はBannerVariants
です。 BannerVariants
でanimationOne
とanimationTwo
の2つのアニメーションを定義します。 これらは、 useCycle
に渡して循環するアニメーションです。
const [animation, cycleAnimation] = useCycle("animationOne", "animationTwo"); useEffect(() => { setTimeout(() => { cycleAnimation(); }, 2000); }, []);
useCycle
は、 useState
フックと同様に機能します。 分解された配列では、 animation
は、 animationOne
またはanimationTwo
のどちらであっても、アクティブなアニメーションを表します。 定義したアニメーション間を循環するcylceAnimation
関数。 循環させたいアニメーションをuseCycleに渡し、 cylceAnimation
で2秒後にuseCycle
を呼び出しuseEffect
。
<div className="App"> <Container> <H1 variants={H1Variants} initial="initial" animate="animate"> Cool Hero Section Anmiation </H1> <HeroSection> <TextBox variants={TextVariants} initial="initial" animate="animate"> Storage shed, troughs feed bale manure, is garden wheat oats at augers. Bulls at rose garden cucumbers mice sunflower wheat in pig. Chainsaw foal hay hook, herbs at combine harvester, children is mallet. Goat goose hen horse. Pick up truck livestock, pets and storage shed, troughs feed bale manure, is garden wheat oats at augers. Lamb. </TextBox> <Banner variants={BannerVariants} animate={animation}> <BannerIllustration /> </Banner> </HeroSection> </Container> </div>
すべての終わりに、バリアントをそれぞれのコンポーネントに渡し、魔法が起こるのを監視します。 これにより、 Banner
は最初にanimationOneで定義したanimationOne
に基づいて右からスライドインし、2秒後にcycleAnimation
が呼び出され、 animationTwo
がトリガーされます。
賢明な豚がかつて言ったように、「それはすべての人々です」。
結論
Framer Motionの基本を理解し、作成できるアニメーションの範囲を垣間見ることができるいくつかのデモプロジェクトを見てきました。 ただし、これを使用するとさらに多くのことができます。 ドキュメントに飛び込んで、ワイルドになることをお勧めします。
資力
- フレーマーモーションApiドキュメント、フレーマーモーション
- react-intersection-observer、npm
- Reactのフレーマーモーション、NetNinja