2025. 7. 27. 12:35ㆍFrontend
< 기대한 애니메이션 >
테이블 탭에서 편집 여부에 따라 위젯 아이콘이 전환되는 애니메이션
편집 상태가 되면 기존 아이콘이 저장 아이콘으로 자연스럽게 전환
문제 상황
아이콘이 전환될 때 아이콘 박스 내부에서만 전환이 일어나야 했어요.
아이콘 박스는 일종의 틀 역할을 해서, 애니메이션도 그 안에 머물러야 해요.
하지만 overflow: hidden을 적용해도 아이콘이 박스 밖으로 튀어나오는 문제가 발생했어요.
원인 분석
첫 번째 이유, position 속성값에 따른 애니메이션
위젯 최상위 컴포넌트에서 overflow가 적용되는 걸 발견했어요.
위젯은 absolute로 띄워져 있는 상태였어요.
그래서 imgBox와 textBox 태그에 position 속성값을 적용해 보면서
overflow가 제대로 작동하는 조건을 실험했어요.

- 적용한 코드
/* index.module.css */
.iconBox {
position: relative; /* 자식 요소의 기준점 설정 O */
overflow: hidden;
}
.textBox {
position: static; /* 자식 요소의 기준점 설정 X */
overflow: hidden;
}
두 번째 이유, AnimatePresence 유무에 따른 차이
또한 AnimatePresence 컴포넌트를 사용할 때와 사용하지 않을 때
레이아웃 애니메이션 동작 방식이 달라지는 것도 확인해봤어요.
// switcher.tsx (AnimatePresence 적용)
<AnimatePresence mode='popLayout' initial={false}>
{!isSaveMode ? (
<motion.img
src={initIconSrc}
alt={alt}
key={initIconSrc}
initial={{ x: '-100%' }}
animate={{ x: '0' }}
exit={{ x: '-100%' }}
/>
) : (
<motion.img
src={changedIconSrc}
alt={alt}
key={changedIconSrc}
initial={{ x: '100%' }}
animate={{ x: '0' }}
exit={{ x: '-100%' }}
/>
)}
</AnimatePresence>
// switcher.tsx (AnimatePresence 미적용)
<>
{!isSaveMode ? (
<motion.img
src={initIconSrc}
alt={alt}
key={initIconSrc}
initial={{ x: '-100%' }}
animate={{ x: '0' }}
exit={{ x: '-100%' }}
/>
) : (
<motion.img
src={changedIconSrc}
alt={alt}
key={changedIconSrc}
initial={{ x: '100%' }}
animate={{ x: '0' }}
exit={{ x: '-100%' }}
/>
)}
</>
분석결과
<AnimatePresence mode="popLayout">는 내부적으로
레이아웃 전환을 위해 position: absolute를 사용하고 있었어요.
이때 부모 position 요소가 기본값(static)이면,
자식의 position 기준이 엉뚱한 곳에 잡혀서 의도치 않은 애니메이션이 되었어요.
“To ensure consistent and expected positioning during a layout animation,
ensure that the animating parent has a position other than static.”
- Motion 공식 문서
또한, 레이아웃 애니메이션은 자식 컴포넌트가 offsetParent의 영향을 받기 때문에,
부모에 transform이 적용되어 있거나 position이 적절하지 않으면
자식 위치 기준이 예기치 않게 변경될 수 있었어요.
따라서 popLayout을 쓸 때는
부모 요소에 position: relative를 명시해야 했어요.
해결방법
문제를 해결하기 위해 .iconBox, .textBox에 다음과 같이 position: relative를 명시적으로 추가했어요.
.iconBox, .textBox {
position: relative; /* 위치 선언 */
overflow: hidden;
}
이렇게 하면 두 요소가 위치 기준 콘텍스트가 되어서,
내부 absolute 요소들이 올바르게 정렬되었어요.
그 결과, 애니메이션이 iconBox와 textBox의 너비 안에서만 일어나게 됐고,
overflow: hidden이 의도한 대로 잘 작동했어요.
또 다른 방법으로 <AnimatePresence>를 제거하면,
문제를 해결할 수 있었어요.

결론
<AnimatePresence mode="popLayout">을 사용할 때
자식 요소의 애니메이션이 부모 박스를 벗어나지 않도록 하려면,
overflow: hidden과 함께 position: relative를 반드시 설정해야 해요.
참고 자료
1. AnimatePresence - Motion 공식 문서
2. position - MDN 공식 문서
3. offsetParent - MDN 공식 문서
'Frontend' 카테고리의 다른 글
| Supabase에서 RLS 적용 후 UPDATE와 DELETE 에러가 반환되지 않는 이유 (3) | 2025.08.10 |
|---|---|
| motion 코드 속에서 찾은 popLayout의 위치 비밀 (1) | 2025.08.03 |
| 탈취자 입장에서 바라본 bcrypt 해싱 (1) | 2025.07.20 |
| then()과 await, 코드 실행 순서가 다른 이유 (0) | 2025.07.05 |
| 노드에서 살펴보는 동기, 비동기 흐름 (0) | 2025.06.29 |