하단 탭바 스크롤 기반 숨김/표시 효과 구현

Facebook 스타일의 스크롤 인터랙션 적용:
- 스크롤 다운 시 탭바 숨김 (translateY + opacity 애니메이션)
- 스크롤 업 시 탭바 표시
- requestAnimationFrame으로 성능 최적화

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-10-16 18:05:24 +09:00
parent 9f6aae2703
commit fd502d71b2
2 changed files with 40 additions and 26 deletions

View File

@@ -296,6 +296,11 @@ footer {
align-items: center;
z-index: 1000;
border-top: 0.1px solid var(--color-E5E5E5);
transition: transform 0.3s ease-in-out;
}
.bottom-tabbar.hidden {
transform: translateY(100%);
}
.tab-button {
@@ -308,9 +313,14 @@ footer {
background: none;
border: none;
cursor: pointer;
transition: all 0.2s ease;
transition: all 0.2s ease, opacity 0.3s ease-in-out;
padding: 8px 4px;
box-sizing: border-box;
opacity: 1;
}
.bottom-tabbar.hidden .tab-button {
opacity: 0.1;
}
.tab-button:hover {

View File

@@ -15,6 +15,7 @@ export const FooterNavigation = ({
}: FooterProps) => {
const { navigate } = useNavigate();
const [isFooterOn, setIsFooterOn] = useState<boolean>(true);
const [isFooterVisible, setIsFooterVisible] = useState<boolean>(true);
const onClickToNavigate = (path?: string) => {
if(!!path){
@@ -97,39 +98,42 @@ export const FooterNavigation = ({
};
useEffect(() => {
let previousTouch: any;
let lastScrollY = 0;
let ticking = false;
const handleTouchStart = (e: TouchEvent) => {
const touch: Touch | undefined = e.touches[0];
previousTouch = touch;
};
const handleTouchMove = (e: TouchEvent) => {
const touch: Touch | undefined = e.touches[0];
let movementY: number | undefined;
if(touch && previousTouch){
movementY = touch.pageY - previousTouch.pageY;
if(movementY > 0){
setIsFooterOn(false);
}
else{
setIsFooterOn(true);
}
};
const handleScroll = () => {
const currentScrollY = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(() => {
// 스크롤 다운 & 일정 거리 이상 스크롤된 경우 -> 숨김
if (currentScrollY > lastScrollY && currentScrollY > 50) {
setIsFooterVisible(false);
}
// 스크롤 업 -> 표시
else if (currentScrollY < lastScrollY) {
setIsFooterVisible(true);
}
lastScrollY = currentScrollY;
ticking = false;
});
ticking = true;
}
};
window.addEventListener('touchstart', handleTouchStart);
window.addEventListener('touchmove', handleTouchMove);
window.addEventListener('scroll', handleScroll, { passive: true });
return () => {
window.removeEventListener('touchstart', handleTouchStart);
window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<>
{ isFooterOn &&
<nav className="bottom-tabbar">
<nav className={`bottom-tabbar ${!isFooterVisible ? 'hidden' : ''}`}>
{ getFooterButtonItems() }
</nav>
}