안녕하세요! 프론트엔드 강사입니다.
오늘은 웹 서핑을 하면서 누구나 한 번쯤 겪어봤을 짜증 나는 현상, 바로 '콘텐츠 점핑(Content jumping)'을 해결해 주는 기특한 CSS 기능인 스크롤 앵커링(Scroll anchoring)에 대해 MDN 공식 문서를 통해 알아보겠습니다.
딱딱한 문서 번역에 그치지 않고, 실무에서 이 기능이 왜 중요하고 어떻게 쓰이는지 제 경험을 녹여서 쉽게 설명해 드릴게요. 자, 시작해 봅시다!
⚠️ 제한적인 지원 (Limited availability)
이 기능은 Safari 등 일부 널리 사용되는 브라우저에서 아직 완벽하게 지원되지 않기 때문에 웹 표준의 기준점인 'Baseline'에 완전히 부합하지는 않습니다. (Chrome, Edge, Firefox 등에서는 잘 지원됩니다.)
웹 사용자라면 스크롤 앵커링이 해결하고자 하는 문제에 대해 이미 잘 알고 계실 겁니다. 느린 인터넷 환경에서 내용이 긴 페이지에 접속한 뒤 글을 읽기 위해 스크롤을 내리기 시작했다고 상상해 보세요. 한참 집중해서 읽고 있는데, 갑자기 내가 보고 있던 화면이 위아래로 '훅' 하고 점프하는 현상 말이죠. 이런 현상은 내가 읽고 있는 글보다 위쪽에 있는 커다란 이미지나 다른 요소들이 뒤늦게 로딩되면서 발생합니다.
스크롤 앵커링(Scroll anchoring)은 브라우저의 내장 기능으로, 사용자가 문서의 새로운 부분으로 이미 스크롤을 내린 후에 콘텐츠가 추가로 로딩될 때 발생하는 이런 '콘텐츠 점핑' 문제를 해결하는 것을 목표로 합니다.
👨🏫 강사님의 꿀팁 & 보충설명:
실무에서 '무한 스크롤(Infinite Scroll)'이나 이미지 지연 로딩(Lazy Loading)을 구현할 때 이 현상이 정말 자주 발생합니다. 예전에는 이걸 막으려고 이미지에 미리 고정된 높이값(min-height)을 주거나 복잡한 자바스크립트 코드를 짜야 했어요. 하지만 이제 브라우저가 알아서 스크롤 위치를 고정해 준다니, 정말 고마운 기능이죠!
스크롤 앵커링은 뷰포트(Viewport, 현재 화면에 보이는 영역) 바깥에서 일어나는 크기 변화를 보정하기 위해 스크롤 위치를 자동으로 조정합니다. 즉, 사용자가 화면에서 바라보고 있던 문서의 지점이 뷰포트 내에 그대로 유지된다는 뜻입니다. 이 말을 다시 해석하면, 문서 전체를 기준으로 사용자가 얼마나 이동했는지를 나타내는 실제 스크롤바의 절대적인 위치(거리)는 내부적으로 변경될 수 있다는 것을 의미합니다.
👨🏫 강사님의 보충설명:
쉽게 말해서, 내 시야 바로 위쪽에 500px짜리 이미지가 늦게 렌더링 되면, 브라우저가 몰래 스크롤바의 위치(scrollTop값)에 500px을 더해버리는 겁니다. 그래서 사용자의 눈에는 화면이 전혀 흔들리지 않은 것처럼 아주 평온하게 보이게 되는 마법 같은 원리랍니다!
여러분은 아무것도 안 하셔도 됩니다! 지원하는 브라우저에서는 이 기능이 기본적으로 활성화(enabled)되어 있습니다. 대부분의 경우 이렇게 앵커링된 스크롤이 바로 여러분이 원하는 동작일 겁니다. 콘텐츠가 멋대로 점프하는 것은 그 누구에게도 좋지 않은 사용자 경험(UX)이니까요.
스크롤 앵커링이 켜져 있는데도 여러분의 페이지가 매끄럽게 동작하지 않는다면, 아마도 여러분이 작성한 자바스크립트의 scroll 이벤트 리스너가 문제일 확률이 높습니다. 앵커 노드가 움직인 것을 보정하기 위해 발생한 추가적인 스크롤 이벤트를 코드가 제대로 처리하지 못하고 있을 수 있거든요.
Firefox 브라우저의 경우, 주소창에 about:config를 입력하고 들어가서 layout.css.scroll-anchoring.enabled 값을 false로 변경해 보면, 스크롤 앵커링을 껐을 때 문제가 해결되는지 확인할 수 있습니다. 또한 layout.css.scroll-anchoring.highlight 설정을 켜면 Firefox가 현재 어떤 요소를 앵커(기준점)로 사용하고 있는지 시각적으로 확인할 수 있습니다. (앵커로 지정된 요소 위에 보라색 오버레이가 표시됩니다.)
만약 브라우저가 선택한 특정 노드가 앵커로 적합하지 않다고 판단되면, 아래 설명해 드릴 overflow-anchor 속성을 사용해서 해당 요소를 앵커 대상에서 제외할 수 있습니다.
CSS 스크롤 앵커링 모듈은 overflow-anchor라는 속성을 제공합니다. 이 속성을 사용하면 문서 전체나 특정 영역에서 스크롤 앵커링 기능을 비활성화할 수 있습니다. 한마디로, 이 자동화된 동작에서 "빠지겠다(opt out)"고 선언하는 방법이죠.
사용할 수 있는 값은 auto 또는 none 두 가지뿐입니다:
auto는 초기값(기본값)입니다. 사용자의 브라우저가 스크롤 앵커링을 지원하기만 한다면 이 동작이 실행되고, 콘텐츠 점핑 현상을 덜 겪게 될 것입니다.none은 문서 전체나 특정 부분을 스크롤 앵커링 대상에서 명시적으로 제외하겠다는 의미입니다.문서 전체에서 이 기능을 끄고 싶다면, HTML의 <body> 요소에 설정하면 됩니다:
body {
overflow-anchor: none;
}
문서의 특정 섹션(영역)에서만 스크롤 앵커링을 끄고 싶다면, 해당 섹션의 컨테이너 요소에 overflow-anchor: none을 설정하세요:
.container {
overflow-anchor: none;
}
주의할 점: 문서 전체나 특정 영역에서 스크롤 앵커링을 껐다면, 그 영역 내부에 있는 자손 요소에서 다시 이 기능을 켤 수는 없습니다. 예를 들어 전체 문서(body)에서 기능을 껐는데, 내부의 특정 서브 섹션에만 overflow-anchor: auto를 설정해서 스크롤 앵커링을 다시 살려내는 것은 불가능합니다.
👨🏫 강사님의 꿀팁:
"이렇게 좋은 기능을 굳이 왜 꺼야 하죠?"라고 생각하실 수 있어요. 가끔 우리가 의도적으로 상단에 요소를 애니메이션으로 스르륵 밀어 넣으면서 화면 전체가 자연스럽게 내려가도록 연출하고 싶을 때가 있습니다. 이때 브라우저가 눈치 없이 "어? 화면이 밀리네? 내가 스크롤 고정해 줄게!" 하고 개입해 버리면 애니메이션이 망가지겠죠. 그럴 때 바로overflow-anchor: none을 사용해서 브라우저를 얌전하게 만드는 겁니다.
스크롤 앵커링 기능이 작동하면 오히려 문제가 발생할 수 있는 특정한 상황들이 있는데, 브라우저는 이를 감지하고 스스로 기능을 비활성화합니다. 이를 억제 트리거(Suppression triggers)라고 부릅니다. 앵커 노드나 그 조상 요소에서 아래의 트리거 중 하나라도 발생하면 앵커링 동작이 억제(취소)됩니다.
이러한 억제 트리거는 다음 속성들의 계산된 값(computed value)에 변화가 생길 때 발동됩니다:
top, left, right, 또는 bottommargin 또는 paddingwidth)나 높이(height)와 관련된 모든 속성들transform과 개별 변형 속성들인 translate, scale, rotate또한, 스크롤 컨테이너 내부 어디에서든 포지션(position) 값에 변화가 생겨도 스크롤 앵커링이 비활성화됩니다.
👨🏫 강사님의 보충설명:
브라우저 입장에서는 요소의margin이나transform값을 동적으로 바꾸는 것을 보면 "아, 개발자가 지금 애니메이션이나 레이아웃 연출을 의도적으로 하고 있구나!"라고 생각하고 조용히 앵커링 기능을 꺼주는 겁니다. 브라우저의 세심한 배려가 돋보이는 부분이죠.
| 명세서 (Specification) |
|---|
| CSS Scroll Anchoring Module Level 1 - #exclusion-api |
아래는 overflow-anchor 속성에 대한 브라우저 호환성 표입니다. (MDN 데이터를 기반으로 번역 및 재구성되었습니다.)
| 브라우저 (Browser) | 데스크톱 (Desktop) 지원 | 모바일 (Mobile) 지원 |
|---|---|---|
| Chrome | ✅ 지원 (버전 56+) | ✅ 지원 (Android 56+) |
| Edge | ✅ 지원 (버전 79+) | 지원 여부 상이함 |
| Firefox | ✅ 지원 (버전 66+) | ✅ 지원 (Android 66+) |
| Opera | ✅ 지원 (버전 43+) | ✅ 지원 (Android 43+) |
| Safari | ⚠️ 개발 중 (Technology Preview) | ❌ 미지원 (iOS) |
| Samsung Internet | - | ✅ 지원 (버전 6.0+) |
| WebView Android | - | ✅ 지원 (버전 56+) |
👨🏫 강사님의 꿀팁:
모바일 Safari(아이폰)에서는 아직 지원하지 않는다는 점을 꼭 유의하세요! 따라서 아이폰 사용자들에게도 매끄러운 스크롤 경험을 제공하고 싶다면, 이미지의 영역을 미리 확보해 두는 고전적인 기법(종횡비 유지 패딩 기법이나 CSSaspect-ratio속성 사용)을 병행하는 것이 좋습니다.
특정 조건에서 스크롤 앵커링 비활성화 가능 여부에 따라 스타일을 다르게 적용하고 싶다면, @supports 특성 쿼리(feature queries)를 사용하여 브라우저가 overflow-anchor 속성을 지원하는지 테스트할 수 있습니다.
오늘 학습은 여기까지입니다! 이제 사용자들에게 화면이 널뛰기하는 불쾌한 경험을 주지 않으려면 브라우저가 어떤 일을 뒤에서 처리해 주고 있는지, 그리고 필요할 땐 어떻게 제어할 수 있는지 감이 잡히셨을 겁니다. 언제든 궁금한 점이 생기면 저한테 다시 질문해 주세요!