CSS position sticky와 fixed 차이
position: sticky와 position: fixed는 스크롤해도 요소를 화면에 머물게 할 때 사용한다.
둘의 결과가 비슷해 보이지만 위치를 계산하는 기준과 문서 흐름에 남는지 여부가 다르다.
fixed는 요소를 문서 흐름에서 빼고 보통 뷰포트에 고정한다.
sticky는 요소의 원래 자리를 유지하면서 지정한 임계점에 도달했을 때만 스크롤 영역에 붙는다.
fixed의 동작
fixed는 요소를 일반적인 문서 흐름에서 제거한다.
다른 요소는 fixed 요소가 없는 것처럼 배치된다.
.floating-button {
position: fixed;
right: 20px;
bottom: 20px;
}이 버튼은 페이지를 어느 정도 스크롤하더라도 보통 뷰포트 오른쪽 아래에 머문다.
top, right, bottom, left 또는 inset 속성으로 고정할 위치를 정한다.
.notice-bar {
position: fixed;
inset: 0 0 auto;
height: 48px;
}상단 공지, 화면 하단 도구 모음, 플로팅 버튼, 모달 배경처럼 화면에 계속 남아야 하는 UI에 잘 어울린다.
sticky의 동작
sticky는 요소를 바로 화면에 고정하지 않는다.
요소는 원래 자리에서 문서와 함께 움직이다가 지정한 위치에 도달하면 그 지점에 머문다.
.section-title {
position: sticky;
top: 0;
}섹션 제목이 화면 상단에 도달하기 전까지는 일반 요소처럼 스크롤된다.
상단에 도달한 후에는 해당 스크롤 영역에 붙어 있는다.
그러나 부모 영역의 끝을 넘어서까지 유지되지는 않는다.
sticky는 부모 영역 안에서만 동작하는 고정 요소가 필요할 때 유용하다.
문서 흐름의 차이
fixed는 문서 흐름에서 빠진다.
따라서 고정 헤더를 만들면 본문의 첫 부분을 가릴 수 있다.
.site-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 64px;
}
main {
padding-top: 64px;
}본문에 헤더 높이만큼 공간을 직접 주어야 겹침을 피할 수 있다.
헤더 높이가 반응형으로 바뀌면 본문 여백도 함께 관리해야 한다.
sticky는 문서 흐름에 자리를 유지한다.
다른 요소는 sticky 요소의 원래 높이를 인식하므로 보통 별도의 여백을 추가할 필요가 없다.
스크롤 기준의 차이
fixed의 containing block은 일반적인 화면 매체에서 뷰포트다.
전체 페이지를 스크롤해도 뷰포트와의 거리가 유지된다.
다만 조상 요소에 transform, perspective, filter 등 containing block을 새로 만드는 속성이 있으면 그 조상이 위치 기준이 될 수 있다.
.app {
transform: translateZ(0);
}
.panel {
position: fixed;
top: 0;
}이 경우 .panel이 뷰포트가 아닌 .app을 기준으로 배치되는지 확인해야 한다.
sticky는 가장 가까운 스크롤 메커니즘을 가진 조상의 영향을 받는다.
.sidebar {
height: 320px;
overflow-y: auto;
}
.sidebar-title {
position: sticky;
top: 0;
}.sidebar-title은 전체 페이지가 아닌 .sidebar 스크롤 영역의 상단에 붙는다.
조상의 overflow 설정을 바꾸면 sticky가 기준으로 삼는 영역도 바뀌 수 있다.
sticky에 top이 필요한 이유
sticky는 어느 지점부터 붙을지 알려 줄 임계값이 필요하다.
.title {
position: sticky;
}이 코드는 스크롤이 되어도 요소가 붙어야 할 위치를 지정하지 않았다.
세로 스크롤에서는 top 또는 bottom 중 하나를 auto가 아닌 값으로 설정해야 한다.
.title {
position: sticky;
top: 16px;
}가로 스크롤에서는 left, right 또는 논리 속성인 inset-inline-start, inset-inline-end를 사용할 수 있다.
sticky가 동작하지 않는 원인
position: sticky가 동작하지 않을 때는 속성 하나보다 주변 레이아웃을 함께 보는 편이 좋다.
첫 번째로 top, bottom, left, right 중 필요한 축의 임계값이 있는지 확인한다.
두 번째로 스크롤할 여분이 있는지 확인한다.
컨테이너와 sticky 요소의 높이가 같거나 내용이 짧아 스크롤이 없으면 붙는 동작을 관찰할 수 없다.
세 번째로 조상의 overflow: hidden, auto, scroll을 확인한다.
예상하지 못한 조상이 스크롤 기준이 되면 전체 페이지를 스크롤해도 움직임이 보이지 않을 수 있다.
네 번째로 flex나 grid 항목이 스트레칭되어 부모와 같은 높이가 되지 않았는지 확인한다.
.layout {
display: grid;
grid-template-columns: 240px 1fr;
align-items: start;
}
.sidebar {
position: sticky;
top: 24px;
}align-items: start는 사이드바가 세로로 불필요하게 늘어나는 것을 막는 데 도움이 된다.
헤더에 적용하는 기준
헤더가 페이지의 첫 부분에 있고 스크롤한 후부터 상단에 남아야 한다면 sticky가 자연스럽다.
.site-header {
position: sticky;
top: 0;
z-index: 10;
background: #fff;
}문서 흐름을 유지하므로 본문 상단 여백을 따로 맞출 일이 줄어든다.
헤더가 DOM의 위치와 관계없이 항상 화면 상단에 있어야 하거나 다른 스크롤 영역의 영향을 받으면 안 된다면 fixed를 검토한다.
fixed를 쓸 때는 헤더가 본문을 가리지 않도록 여백을 함께 설계해야 한다.
z-index와 배경
fixed와 sticky는 둘 다 stacking context를 만든다.
스크롤 중 다른 요소가 위로 올라오면 z-index만 크게 올리기 전에 조상의 stacking context를 함께 확인해야 한다.
.sticky-toolbar {
position: sticky;
top: 0;
z-index: 20;
background-color: #fff;
}배경을 지정하지 않으면 아래로 지나가는 텍스트가 투명한 요소 뒤에 비쳐 가독성이 떨어질 수 있다.
모바일 UI의 주의점
fixed 하단 바는 모바일 브라우저 UI나 기기의 safe area와 겹칠 수 있다.
.bottom-actions {
position: fixed;
right: 0;
bottom: 0;
left: 0;
padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
}본문의 마지막 내용이 하단 바에 가려지지 않도록 본문에도 충분한 하단 여백을 주어야 한다.
화면을 크게 확대했을 때 fixed 요소가 내용을 가리지 않는지도 확인한다.
고정 UI가 많아질수록 실제 본문을 볼 수 있는 영역은 줄어든다.
선택 기준
화면의 같은 위치에 항상 남아야 한다면 fixed를 쓴다.
원래 자리에서 시작해 특정 스크롤 영역 안에서만 머물러야 한다면 sticky를 쓴다.
플로팅 버튼, 전체 화면 모달, 하단 작업 바는 fixed가 잘 어울린다.
긴 목록의 섹션 제목, 문서 목차, 상품 페이지의 옵션 패널은 sticky가 잘 어울린다.
선택 후에는 위치 기준, 문서 흐름, 부모의 overflow, 겹침, 모바일 화면을 함께 확인한다.
position의 기준 요소가 더 필요하면 CSS position relative와 absolute 차이를 함께 보면 좋다.
참고 자료





