[Framer motion] アニメーション動作後にposition: fixedが効かない時の対処法
バージョン
react: 18.2.0
framer-motion: 10.18.0
問題発生までの道のり
Framer motionを使って、アニメーションありのヘッダーを作成していました。
スクロール量やスクロールの向きに応じて、表示・非表示が切り替わるようにしています。
参考Youtube
Header実装例
'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
が指定されたナビゲーションメニューが画面全体に表示される仕様です。
ページに遷移して、何もスクロールしないでハンバーガーメニューをクリックすると綺麗にナビゲーションメニューが画面いっぱいに表示されます。
いい感じです。
しかし、問題はヘッダーのアニメーションを動作させた後に起こりました。
アニメーション起動後に、ハンバーガーメニューをクリックすると何故か画面全体にナビゲーションメニューが表示されません。
その親要素であるヘッダーの要素全体に対して、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
Discussion