🤕

[Framer motion] アニメーション動作後にposition: fixedが効かない時の対処法

2024/01/14に公開

バージョン

react: 18.2.0
framer-motion: 10.18.0

問題発生までの道のり

Framer motionを使って、アニメーションありのヘッダーを作成していました。
スクロール量やスクロールの向きに応じて、表示・非表示が切り替わるようにしています。

参考Youtube
https://www.youtube.com/watch?v=qc2kQcicNNc

Header実装例
Header.tsx
'use client';
import {motion, useMotionValueEvent, useScroll} from 'framer-motion'
import Navbar from '@/ui/Navbar';

export default funciton Header(){
  const {scrollY} = useScroll();
  const [hidden, setHidden] = useState(false);
  
  useMotionValueEvent(scrollY, 'change', (latest) => {
    const previous = scrollY.getPrevious();
    if(latest > previous && latest > 120){
      setHidden(true);
    }else{
      setHidden(false);
    }
  });
  
 return (
   <motion.header
     className="fixed right-0 top-0 z-20 bg-white"
     variants={{
       visible: {
         y:0,
       },
       hidden: {y: '-100%'}
     }}
     animate={hidden ? 'hidden' : 'visible'}
     transition={{duration: 0.35, ease: 'easeInOut'}}
   >
    <Link href={'/'}>
      <Image src="/img/icon.svg">
    </Link>
    <Navbar />
   </motion.header>
 );
};

ヘッダーがSPサイズの場合はハンバーガーメニューを表示させていました。
ハンバーガーメニューをクリックするとposition:fixedが指定されたナビゲーションメニューが画面全体に表示される仕様です。

Navbar実装例

ページに遷移して、何もスクロールしないでハンバーガーメニューをクリックすると綺麗にナビゲーションメニューが画面いっぱいに表示されます。
いい感じです。


しかし、問題はヘッダーのアニメーションを動作させた後に起こりました。
アニメーション起動後に、ハンバーガーメニューをクリックすると何故か画面全体にナビゲーションメニューが表示されません。
その親要素であるヘッダーの要素全体に対して、position:fixedが効いてしまうようになりました。

原因

ナビゲーションメニューの親要素であるヘッダーのstyleタグにtransformが存在していることです。

問題無しパターン

style="transform: none"
position: fixed画面全体に対して適用される

問題発生パターン

style="transform: translateY(0%) translateZ(0%)"
position: fixed親要素全体に対して適用される

解決策

transitionEndを利用して、transformの値を上書きしてやりましょう。
今回問題になっているのはmotion.header部分なのでそのvariants内にtransitionEndを追加しましょう。

 <motion.header
   variants={{
     visible: {
       y:0,
+      transitionEnd: {x:0, y:0} 
     }
   }}
 >
 </motion.header>

この記述をすることで、transformの値をアニメーション終了後にtransform: noneに上書きしています。
これで、framer motionのアニメーションが動いた後でも、画面全体に対してposition: fixedを適用させることができました。

この挙動については、Chrome側のバグらしいのでFramer motionは何も悪くないらしいです。
Chrome側で早めに修正されることを祈ります🙏

参考Issue

https://github.com/framer/motion/issues/823#issuecomment-1276670313

Discussion