Vue
iOS에서 뒤로 가기 후 화면이 비어 보이는 문제 (Vue Router scrollBehavior)
Safari와 iOS 웹뷰에서 콘텐츠를 보다가 뒤로 가기를 하면, 가끔 헤더와 콘텐츠가 그려지지 않고 빈 화면처럼 보인다는 제보를 받았습니다.
처음 의심한 것들
처음에는 렌더링 문제라고 생각했습니다. 헤더가 position: sticky로 되어 있어서 transform: translateZ(0)처럼 레이어를 분리하는 방법을 적용해 보고, BFC 관련 자료도 찾아봤지만 증상은 그대로였습니다.
재현 규칙 찾기
여러 번 재현해 보니 규칙이 있었습니다.
| 동작 | 결과 |
|---|---|
| 스크롤 후 이동 → 스크롤 후 뒤로 가기 | 정상 |
| 스크롤 후 이동 → 바로 뒤로 가기 | 빈 화면 발생 |
스크롤이 관련 있다는 걸 알고 나서, 페이지를 이동할 때 화면이 맨 위로 먼저 올라간 뒤 이동하는 현상이 눈에 들어왔습니다. 코드를 찾아보니 router.beforeEach 안에서 window.scrollTo(0, 0)을 호출하고 있었습니다.
해결: scrollBehavior 사용
Vue Router가 제공하는 scrollBehavior로 스크롤 처리를 옮기자 문제가 사라졌습니다.
// router/index.ts
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior() {
return { x: 0, y: 0 };
},
});
scrollBehavior는 to, from, savedPosition을 인자로 받습니다. savedPosition은 브라우저의 뒤로 가기·앞으로 가기로 이동했을 때 이전 스크롤 위치를 담고 있어서, 이전 위치를 유지하려면 아래처럼 쓸 수 있습니다.
// router/index.ts
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
return { x: 0, y: 0 };
},
});
원인 추정
정확한 원인은 확인하지 못했지만, 다음과 같이 추정하고 있습니다.
beforeEach는 이동하기 전 페이지의 스크롤을 맨 위로 올립니다.- 바로 뒤로 가기를 하면 브라우저가 스크롤 위치를 복원하는 과정과 겹치면서, iOS에서 화면이 제대로 다시 그려지지 않은 것으로 보입니다.
- 반면
scrollBehavior는 이동이 끝난 뒤 스크롤을 처리하기 때문에 이런 충돌이 생기지 않았습니다.
라우터 이동과 관련된 스크롤 처리는 전역 가드보다 scrollBehavior에서 하는 것이 안전하다는 걸 배운 경험이었습니다.
댓글 0