JIHYEONJEONG
Next.js

nextjs - scroll 위치 유지하기

Nextjs에서 탭 내비게이션으로 이동해도 스크롤 위치가 초기화되지 않도록 하는 방법을 설명합니다.

예제

Problem - Nextjs에서 탭 내비게이션으로 이동하면 스크롤 위치가 초기화된다.

이전에 탭 내비게이션을 작성한 뒤 겪었던 문제는 url이 변화하면 기존 포커스되어있던 스크롤 포지션이 초기화되어 처음부터 시작한다는 것이었다.

React였다면 tab을 클라이언트 렌더링으로 구현했을 것이므로 이 고민을 할 필요가 없겠지만 Nextjs에서는 라우트가 변경된다 = Nextjs app router로 인해 페이지가 서버로부터 새로 렌더링된다는 것을 의미한다.

Goal - Tab 내비게이션으로 url 라우팅이 변경되어도 스크롤 위치를 유지해야 한다.

mdn - scroll restoration의 설명은 다음과 같다.

scrollRestoration 속성은 웹 어플리케이션이 history 내비게이션을 진행할 경우 스크롤 위치를 복원할 것인지를 결정할 수 있다.

medium blog에서는 조금 더 실전적인 설명을 찾을 수 있었다.

전통적인 웹 프레임워크에서 route를 이동하게 되면 기본적으로 페이지의 top으로 스크롤이 이동하게 됩니다. 하지만 최근의 모던한 웹 앱에서는 스크롤 포지션을 유지해야 하는 경우가 있죠. Nextjs15에서는 새로운 scroll 프로퍼티를 추가해서 스크롤 위치를 되살리는 기능을 제공하고 있습니다.

Implementation - scroll= 옵션을 사용해보자.

'use client'
...
 <nav className="flex items-center gap-1">
          {navItems.map((item) => {
            const isActive = pathname.includes(item.href);
            return (
              <Link
                scroll={false} // 스크롤 유지
                key={item.href}
                href={item.href}
                className={`px-4 py-2 rounded-md text-sm font-medium transition-all }`}
    >
                {item.name}
              </Link>
            );
          })}
        </nav>
...

programmatical하게 이동하는 경우도 마찬가지이다.

    router.push(`/products?category=${filter}`, { scroll: false })

라우트 변경 시 특정한 위치로 이동하게 하거나, 멀티 스텝 폼을 사용하고 그에 따른 특별한 규칙이 있거나, infinite 스크롤을 사용하는 리스트가 있거나... scroll= 대신 리액트 로직을 사용하는 경우도 있을 것이지만, 여기서는 위 기본적인 task에 대해서만 작성하고 추후에 또 revisit하는 것으로 한다.

Summary

여기서는 여러 파생될 시나리오 중 해결해야 할 하나, 링크 및 router.action 시의 스크롤 복원만을 다루었다. Nextjs 15 버전에서 추가된 scroll: false 옵션을 통해 해결할 수 있었다. 추가적으로 아래 링크를 통해 더 다양한 라우트 이동 시나리오에 대해 고민해볼 수 있을 것 같다.

Refs

mdn - scroll restoration 올리브영 스크롤 위치 복원 시나리오

On this page