iOS에서 뒤로 가기 후 화면이 비어 보이는 문제 (Vue Router scrollBehavior)

0 0 0

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