스크롤은 건드리지마!!
이 글은 Don’t Fuck With Scroll의 문제 제기에서 출발해, 구현 방식과 검증 기준을 덧붙인 의견 글입니다.
웹 페이지를 읽으러 왔지, 놀이기구를 타러 온 게 아닙니다. 휠을 멈췄는데 콘텐츠가 계속 미끄러지거나 원하는 단락을 지나쳐 버리는 페이지를 만나면 이런 생각이 들어요.
제가 반대하는 것은 사용자의 스크롤 입력을 가로채 사이트만의 속도와 관성을 강제하는 것입니다. 부드럽게 움직인다는 이유만으로 모든 스크롤을 같은 문제로 묶을 필요는 없습니다.
같은 ‘부드러운 스크롤’도 구현은 다르다
| 방식 | 누가 이동을 결정하는가 | 살펴볼 점 |
|---|---|---|
| OS·브라우저 기본 관성 | 플랫폼의 입력 처리 | 사용자가 익숙한 기본 동작 유지 |
CSS scroll-behavior: smooth | 브라우저가 앵커·API 이동을 처리 | 모션 선호와 이동 목적 |
| 휠·터치 입력을 취소하고 별도 애니메이션 | 사이트의 JavaScript | 반응 지연, 중단, 초점, 브라우저 기능 |
| 스크롤에 맞춰 장식을 애니메이션 | 스크롤은 기본 동작, 장식은 별도 | 시각적 움직임과 렌더링 비용 |
scroll-behavior는 앵커 탐색이나 스크롤 API로 발생한 이동에 적용됩니다. 휠과 트랙패드의 직접 입력에 관성을 새로 입히는 속성이 아닙니다. W3C CSS Overflow 명세
따라서 플러그인의 이름보다 실제로 기본 입력을 취소하는지, 콘텐츠의 위치를 무엇으로 이동하는지 확인하는 것이 먼저입니다.
문제는 입력과 결과 사이의 거리가 늘어난다는 것
문서를 읽을 때 스크롤은 내용을 예측 가능한 만큼 이동시키는 조작입니다. 여기에 긴 보간 애니메이션을 넣으면 손의 입력과 화면 위치가 어긋날 수 있어요. 특히 빠르게 훑다가 원하는 곳에서 멈추는 동작을 반복할수록 불편이 드러납니다.
또한 시각적 움직임에 민감한 사용자에게 과한 이동 효과가 어려움을 줄 수 있습니다. WCAG의 상호작용 애니메이션 기준은 필수가 아닌 동작 애니메이션을 끌 수 있어야 한다고 설명합니다. 이 항목은 2.3.3, AAA 등급입니다. 모든 smooth scroll이 자동으로 접근성 위반이라는 뜻으로 확대하면 안 됩니다. WCAG 2.3.3 해설
중요한 것은 예쁜 데모에서 느낀 인상이 아니라, 콘텐츠를 찾아 읽는 동안 사용자가 통제할 수 있는가입니다.
기본 스크롤을 대체하면 떠안는 일
컨테이너를 transform으로 움직이는 식의 구현을 선택하면 시각적 위치와 브라우저가 관리하는 스크롤 위치가 다를 수 있습니다. 이 경우 앵커 이동, 초점, 뒤로 가기 복원 등이 라이브러리와 어떻게 연결되는지 확인해야 해요. 모든 플러그인이 이 기능을 깨뜨리는 것은 아니지만, 직접 대체한 만큼 검증 책임이 늘어납니다.
키보드 접근도 마찬가지입니다. 포인터로만 이동할 수 있는 화면을 만들지 않아야 하고, Tab으로 초점을 옮겼을 때 해당 요소를 볼 수 있어야 합니다. 키보드 조작 가능성은 별도의 WCAG 2.1.1 A 등급 기준입니다. WCAG 키보드 기준
성능 역시 “플러그인이 있으니 느리다”로 끝낼 문제는 아닙니다. 프레임마다 수행하는 계산, 레이아웃 읽기·쓰기, 그리는 영역이 실제 비용을 결정해요. 효과를 켰을 때와 껐을 때 같은 기기에서 스크롤하며 프레임과 메인 스레드 작업을 비교해야 원인을 좁힐 수 있습니다.
앵커 이동이 목적이라면 작은 구현부터
목차를 눌렀을 때 단락으로 이동시키는 정도라면 기본 앵커 링크에서 시작할 수 있습니다.
1
2
<a href="#installation">설치 방법으로 이동</a>
<h2 id="installation">설치 방법</h2>
1
2
3
4
5
6
7
8
9
10
11
/* 고정 헤더에 제목이 가리지 않도록 프로젝트에 맞게 조절 */
h2[id] {
scroll-margin-top: 5rem;
}
/* 모션을 줄이도록 설정한 사용자에게는 기본적인 즉시 이동 유지 */
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
이 코드는 preventDefault()로 링크를 가로채지 않습니다. 모션 선호가 바뀌면 CSS 미디어 쿼리도 다시 적용돼요. 별도로 scrollTo({ behavior: 'smooth' })나 JavaScript 애니메이션을 호출한다면 그 경로에도 같은 선호를 반영해야 합니다. CSS 한 곳을 설정했다고 모든 스크립트 효과가 비활성화되는 것은 아닙니다.
scroll-margin-top의 목적은 도착 위치의 여백을 정하는 것입니다. 모션과 별개의 문제이므로 효과를 꺼도 제목이 가려지지 않는지 확인하면 좋습니다. W3C scroll-margin 정의
유지할 가치가 있는 효과인지 확인하기
스크롤 연출이 핵심인 전시형 페이지라면 효과를 남기는 선택도 가능합니다. 다만 다음을 같은 콘텐츠의 기본 스크롤 버전과 비교해보면 좋겠습니다.
| 시도할 작업 | 확인할 동작 |
|---|---|
| 휠·트랙패드·터치로 빠르게 이동 후 멈추기 | 입력을 멈추거나 반대로 움직였을 때 통제할 수 있는가 |
| Tab, Page Down, Home/End 사용 | 요소에 도달하고 초점 위치를 볼 수 있는가 |
목차 클릭, URL의 #id로 직접 진입 | 원하는 단락에 정확히 도착하는가 |
| 브라우저 뒤로 가기, 페이지 내 검색 | 기존 읽던 위치와 검색 결과를 찾을 수 있는가 |
| 동작 줄이기 설정 켜기 | 콘텐츠와 기능을 유지하면서 불필요한 움직임이 줄어드는가 |
| 성능이 낮은 실제 기기에서 읽기 | 애니메이션 때문에 읽기와 조작이 끊기지 않는가 |
이 목록을 통과했다고 모든 접근성이 증명되지는 않습니다. 다만 마우스로 데모를 한 번 보는 것보다, 기본 조작을 바꾸면서 생긴 회귀를 구체적으로 찾을 수 있어요.
저는 일반적인 블로그, 문서, 업무 화면에서는 기본 스크롤을 출발점으로 두는 편이 맞다고 봅니다. 연출이 콘텐츠를 이해하는 데 주는 가치가 입력 지연과 구현·유지보수 비용보다 큰지 설명할 수 있을 때만 더하는 거죠. 스크롤이 눈에 띄는 것보다, 사용자가 원하는 곳에서 편하게 읽는 것이 먼저입니다.