목차 링크를 눌렀더니 제목이 sticky 헤더 뒤에 가려진 이유
문제 발생
글 안의 목차에서 항목을 누르면 해당 섹션으로 이동은 하는데, 제목 줄이 sticky 헤더에 가려서 본문 중간부터 보였습니다.
<a href="#origin">원인 분석</a>
...
<h2 id="origin">원인 분석</h2>padding-top을 주면 여백이 실제로 생겨 레이아웃이 벌어졌고, 음수 마진으로 상쇄하는 방법은 클릭 영역이 어긋났습니다.
원인 분석
앵커로 이동하면 브라우저는 대상 요소의 위쪽 가장자리를 스크롤 컨테이너의 맨 위에 맞춥니다. 그 자리에 position: sticky인 헤더가 떠 있으면 헤더가 제목을 덮습니다. 브라우저는 헤더의 존재를 모르므로 알아서 비켜 주지 않습니다.
scroll-margin-top은 이 계산에만 쓰이는 여백입니다. 레이아웃에는 영향을 주지 않고, 스크롤이 멈출 위치만 그만큼 아래로 내립니다. 2021년 4월부터 Baseline입니다.
비슷한 이름의 scroll-padding-top은 스크롤 컨테이너 쪽에 거는 속성입니다. "이 컨테이너의 위 60px에는 무엇도 붙이지 마라"는 의미이고, scroll-margin-top은 "나를 붙일 때 60px 띄워라"라는 요소 쪽 선언입니다. 헤더 하나에 대해서라면 컨테이너에 한 번 거는 scroll-padding-top이 더 간단할 때도 많습니다.
해결 방안
- 앵커 대상이 되는 요소에 헤더 높이만큼 줍니다.
:target,
h2[id],
h3[id] {
scroll-margin-top: var(--header-height);
}- 또는 스크롤 컨테이너에 한 번만 겁니다. 대상마다 챙기지 않아도 되어 관리가 쉽습니다.
html {
scroll-padding-top: var(--header-height);
}- 헤더 높이를 토큰으로 관리합니다. 숫자를 두 곳에 적으면 반드시 어긋납니다. 이 저장소는 헤더의 실제 점유 높이(내용 3.5rem + 아래 보더 1px)를 변수 하나로 내보내고, 그 값을 빼는 곳마다 참조합니다.
scroll-behavior: smooth와 함께 쓸 때는 접근성을 챙깁니다. 부드러운 스크롤은 화면 전체가 흐르는 움직임이라prefers-reduced-motion: reduce에서는 꺼 주는 편이 좋습니다.- 스크롤 스냅에도 같은 속성이 쓰입니다. 원래 스크롤 스냅의 정지 위치를 조정하는 속성이고, 앵커 이동에도 적용되는 것입니다. 캐러셀에서 항목이 가장자리에 딱 붙는 게 싫을 때 같은 방식으로 조절할 수 있습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.