
배지를 카드 모서리에 놓았는데 화면 모서리로 이동하거나, 고정한 메뉴가 본문을 가리는 문제는 좌표보다 기준 상자를 먼저 확인하면 이해하기 쉽습니다. 이 글에서는 relative, absolute, fixed, sticky를 같은 실습 페이지에서 비교합니다. 기본 흐름을 유지하는지, 어느 상자를 기준으로 움직이는지, 스크롤할 때 무엇이 달라지는지가 핵심입니다.
position을 고르기 전에 일반 흐름부터 확인하세요
문단과 카드가 순서대로 놓이는 기본 상태는 static입니다. 두 열을 만들거나 카드 간격을 맞추는 작업은 Flex나 Grid로 처리하고, 특정 요소를 겹치거나 스크롤 중 유지할 필요가 있을 때 위치 지정을 선택하세요. 위치 지정으로 모든 배치를 만들면 텍스트가 늘어날 때 아래 콘텐츠가 자연스럽게 밀려나지 않아 유지 관리가 어려워집니다.
실습의 A, B, C는 Flex로 배치되어 있습니다. B에 relative와 top: 8px을 적용하면 B의 그림만 아래로 이동하고 원래 차지하던 자리는 남습니다. C가 B의 새 위치를 따라 이동하지 않는 점을 보세요. 따라서 relative의 오프셋은 여백을 만드는 대체 수단이 아닙니다. 실제 간격을 바꾸려면 gap이나 margin을 먼저 검토하는 편이 의도를 잘 드러냅니다.
absolute가 찾는 기준 부모를 직접 비교하세요
absolute는 일반 흐름에서 빠지므로 다른 콘텐츠가 그 공간을 자동으로 비워 주지 않습니다. 실습의 실패 카드는 position을 지정하지 않았고 바깥 실험판만 relative입니다. 따라서 배지가 카드가 아니라 실험판 오른쪽 위에 놓입니다. 이는 페이지 전체를 깨뜨리지 않도록 범위를 제한한 의도적인 실패입니다. 수정 카드에는 relative를 추가해 배지가 사용할 기준 상자를 만듭니다. 카드의 위쪽 padding은 배지와 제목이 겹치지 않게 하는 별도의 공간 설계입니다.
실제 프로젝트에서 기준을 찾을 때는 DOM 부모 한 단계만 보지 말고 조상 방향으로 올라가며 계산된 스타일을 확인하세요. 위치 지정 외에도 transform 같은 속성이 containing block을 만들 수 있습니다. 여기서는 그런 조건을 섞지 않아 relative 유무 한 가지만 비교합니다. 개발자 도구에서 수정 카드의 relative를 잠시 끄면 두 사례가 같아지는 이유를 관찰할 수 있습니다.
fixed에는 가려질 콘텐츠를 위한 공간이 필요합니다
실습의 안내줄은 fixed로 화면 위에 남습니다. 높이를 64px로 정하고 body에 같은 상단 padding을 주어 첫 문장이 안내줄 아래에서 시작하게 했습니다. 앵커 링크로 본문에 이동할 때는 scroll-padding-top도 도움이 됩니다. 다만 안내문이 여러 줄로 늘어나는 제품에서는 고정 높이가 내용과 맞는지 다시 설계해야 합니다. 고정 요소 자체가 문서 높이를 밀어 준다고 기대해서는 안 됩니다.
보통 fixed는 뷰포트를 기준으로 생각할 수 있지만 모든 상황에서 그렇지는 않습니다. 예를 들어 조상에 transform이 있으면 그 조상이 fixed의 기준을 만들 수 있습니다. 이 예제는 안내줄을 body 바로 아래에 두고 그러한 조상 효과를 만들지 않습니다. 화면 전체의 안내가 목적이라면 먼저 DOM 위치와 조상 스타일을 확인한 다음 좌표를 조절하세요.
sticky가 붙지 않을 때 확인할 세 가지
sticky는 흐름 안의 자리를 유지하면서 가까운 스크롤포트를 기준으로 위치를 조정합니다. 이 예제는 높이 300px인 overflow: auto 영역 안에 충분히 긴 본문을 넣었습니다. 실패 제목에는 top이 없고 수정 제목에는 top: 0이 있습니다. 세로 방향의 양쪽 inset이 모두 auto라면 해당 방향에서 붙는 동작을 기대할 수 없습니다. 두 제목이 처음에는 함께 보이다가 스크롤 후 다르게 움직이는지 비교하세요.
먼저 top 같은 임계값이 있는지, 다음으로 실제로 스크롤하는 조상이 누구인지, 마지막으로 요소가 움직일 공간이 충분한지 보세요. 부모 높이와 자식 높이가 비슷하면 관찰할 이동 구간이 거의 없습니다. 조상의 overflow 설정 때문에 예상과 다른 스크롤 기준이 생기는 경우도 있습니다. sticky는 부모 경계를 무시하는 fixed가 아니므로 컨테이너 끝에 도달한 뒤에도 계속 화면에 남는다고 가정하지 마세요.
직접 확인하는 순서
시작 파일에서는 수정 카드의 기준과 sticky 임계값이 비어 있습니다. 먼저 파일을 열어 실패 모습을 관찰하고 두 연습용 주석을 채우세요. 완성본에서 카드 배지가 카드 안에 들어오는지, 내부 스크롤과 문서 스크롤이 서로 다른지, 좁은 화면에서 상단 안내가 첫 문장을 덮지 않는지 확인하세요. 글자 크기를 키워도 같은 질문을 반복하면 위치만 맞춘 코드와 내용 변화까지 고려한 코드를 구별할 수 있습니다.

완성 HTML 전체 코드
아래 코드를 index.html로 저장하고 같은 폴더에 style.css를 만드세요. 시작 파일의 연습용 주석을 먼저 작성한 뒤 완성본과 비교해도 좋습니다.
실습 파일
파일 경로를 확인하고 같은 프로젝트 안에 저장하세요. 이미지 등 소스 목록에 없는 파일과 실행 안내는 실습 ZIP에 포함되어 있습니다.
배치 기준이 되는 조상과 스크롤 컨테이너를 확인해 position 동작을 구분합니다. 수정 전은 시작 상태, 수정 후는 비교할 완성 상태입니다.
수정 전
index.html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CSS position 완전 이해: relative·absolute·fixed·sticky 실습</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<p class="note" style="padding: 16px">
시작 파일: 수정 영역의 설명은 완성 목표입니다. style.css의 연습 주석에 안내된
규칙을 적용해 보세요.
</p>
<header class="fixed-bar"><a href="#start">POSITION LAB · 본문 시작</a></header>
<main id="start">
<h1>기준점을 바꾸면 위치가 달라집니다</h1>
<p>상단 안내는 fixed입니다. 문서에는 같은 높이의 공간을 확보했습니다.</p>
<section>
<h2>1. relative: 원래 자리는 유지</h2>
<div class="flow">
<span>A</span><span class="relative-box">B · 아래로 8px</span><span>C</span>
</div>
<p class="note">B를 이동해도 A와 C의 배치 기준은 그대로입니다.</p>
</section>
<section>
<h2>2. absolute: 기준 부모 비교</h2>
<div class="position-lab">
<p>실패 실험 · 배지가 바깥 실험판을 기준으로 배치됩니다.</p>
<article class="card broken">
<h3>부모 기준 없음</h3>
<p>배지는 카드 오른쪽 위를 의도했습니다.</p>
<span class="badge">실패 배지</span>
</article>
</div>
<div class="position-lab">
<p>수정 · 카드에 position: relative</p>
<article class="card repaired">
<h3>부모 기준 있음</h3>
<p>배지 공간도 카드 안에 확보합니다.</p>
<span class="badge">수정 배지</span>
</article>
</div>
</section>
<section>
<h2>3. sticky: 이 영역 안에서 스크롤</h2>
<p id="scroll-help">
실패 제목은 top이 없어 함께 사라집니다. 수정 제목은 위에 붙습니다. 아래 영역에
초점을 두고 방향키로도 스크롤할 수 있습니다.
</p>
<div
class="scroll-lab"
tabindex="0"
role="region"
aria-label="Sticky 스크롤 실험"
aria-describedby="scroll-help"
>
<div class="sticky-content">
<h3 class="sticky-broken">실패 · top 없음</h3>
<h3 class="sticky-fixed">수정 · top: 0</h3>
<p>스크롤 시작: 수정 제목이 영역 상단에 도착하는 순간을 보세요.</p>
<p class="scroll-space">
긴 본문 구간입니다. 스크롤해도 제목은 이 스크롤 영역을 기준으로 붙습니다.
</p>
<p>본문 끝: sticky는 자신의 컨테이너 경계를 무한히 벗어나지 않습니다.</p>
</div>
</div>
</section>
<section>
<h2>4. fixed: 문서 스크롤로 확인</h2>
<p>
이 문단까지 문서 전체를 스크롤해 보세요. 상단 링크는 화면 위에 남습니다. 작은
화면에서도 안내가 본문 첫 줄을 가리지 않는지 확인하세요.
</p>
</section>
</main>
</body>
</html>
style.css
* {
box-sizing: border-box;
}
body {
margin: 0;
background: #f4f4f4;
color: #252525;
font-family: system-ui, sans-serif;
line-height: 1.65;
}
main {
width: min(100% - 32px, 880px);
margin: 40px auto;
}
h1 {
font-size: clamp(1.6rem, 4vw, 2.5rem);
line-height: 1.3;
}
h2 {
font-size: 1.25rem;
}
section {
margin-block: 32px;
padding-block: 12px;
border-top: 1px solid #aaa;
}
a {
color: inherit;
text-underline-offset: 4px;
}
a:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
outline: 3px solid #444;
outline-offset: 4px;
}
code {
overflow-wrap: anywhere;
}
.note {
color: #505050;
}
.fixed-bar {
position: fixed;
inset: 0 0 auto;
height: 64px;
display: grid;
place-items: center;
background: #dedede;
z-index: 2;
}
body {
padding-top: 64px;
}
html {
scroll-padding-top: 80px;
}
.flow {
display: flex;
gap: 24px;
padding: 16px;
background: #e1e1e1;
}
.flow span {
padding: 8px;
background: #ccc;
}
.relative-box {
position: relative;
top: 8px;
}
.position-lab {
position: relative;
padding: 56px 16px 16px;
margin-block: 20px;
background: #e6e6e6;
}
.card {
padding: 52px 16px 16px;
background: #fff;
}
.repaired {
/* 연습: 배지의 기준 부모를 지정하세요. */
}
.badge {
position: absolute;
top: 12px;
right: 12px;
padding: 3px 8px;
background: #444;
color: #fff;
}
.scroll-lab {
height: 300px;
overflow: auto;
background: #e5e5e5;
}
.sticky-content {
padding: 0 16px 20px;
}
.sticky-broken,
.sticky-fixed {
position: sticky;
margin: 0;
padding: 12px;
background: #ccc;
}
.sticky-fixed {
/* 연습: top 임계값을 추가하세요. */
background: #333;
color: #fff;
}
.scroll-space {
min-height: 420px;
padding-block: 40px;
}
수정 방법
index.html
index.html에서 아래 차이가 있는 위치를 수정하세요. -는 삭제할 줄, +는 추가할 줄이며 표시는 실제 코드에 넣지 않습니다.
배치 기준이 되는 조상과 스크롤 컨테이너를 확인해 position 동작을 구분합니다.
--- 수정 전/index.html
+++ 수정 후/index.html
@@ -7,10 +7,6 @@
<link rel="stylesheet" href="style.css" />
</head>
<body>
- <p class="note" style="padding: 16px">
- 시작 파일: 수정 영역의 설명은 완성 목표입니다. style.css의 연습 주석에 안내된
- 규칙을 적용해 보세요.
- </p>
<header class="fixed-bar"><a href="#start">POSITION LAB · 본문 시작</a></header>
<main id="start">
<h1>기준점을 바꾸면 위치가 달라집니다</h1>
수정 후 탭의 전체 파일과 비교한 뒤 본문의 확인 절차를 실행하세요.
style.css
style.css에서 아래 차이가 있는 위치를 수정하세요. -는 삭제할 줄, +는 추가할 줄이며 표시는 실제 코드에 넣지 않습니다.
배치 기준이 되는 조상과 스크롤 컨테이너를 확인해 position 동작을 구분합니다.
--- 수정 전/style.css
+++ 수정 후/style.css
@@ -80,7 +80,7 @@
background: #fff;
}
.repaired {
- /* 연습: 배지의 기준 부모를 지정하세요. */
+ position: relative;
}
.badge {
position: absolute;
@@ -106,7 +106,7 @@
background: #ccc;
}
.sticky-fixed {
- /* 연습: top 임계값을 추가하세요. */
+ top: 0;
background: #333;
color: #fff;
}
수정 후 탭의 전체 파일과 비교한 뒤 본문의 확인 절차를 실행하세요.
수정 후
index.html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CSS position 완전 이해: relative·absolute·fixed·sticky 실습</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header class="fixed-bar"><a href="#start">POSITION LAB · 본문 시작</a></header>
<main id="start">
<h1>기준점을 바꾸면 위치가 달라집니다</h1>
<p>상단 안내는 fixed입니다. 문서에는 같은 높이의 공간을 확보했습니다.</p>
<section>
<h2>1. relative: 원래 자리는 유지</h2>
<div class="flow">
<span>A</span><span class="relative-box">B · 아래로 8px</span><span>C</span>
</div>
<p class="note">B를 이동해도 A와 C의 배치 기준은 그대로입니다.</p>
</section>
<section>
<h2>2. absolute: 기준 부모 비교</h2>
<div class="position-lab">
<p>실패 실험 · 배지가 바깥 실험판을 기준으로 배치됩니다.</p>
<article class="card broken">
<h3>부모 기준 없음</h3>
<p>배지는 카드 오른쪽 위를 의도했습니다.</p>
<span class="badge">실패 배지</span>
</article>
</div>
<div class="position-lab">
<p>수정 · 카드에 position: relative</p>
<article class="card repaired">
<h3>부모 기준 있음</h3>
<p>배지 공간도 카드 안에 확보합니다.</p>
<span class="badge">수정 배지</span>
</article>
</div>
</section>
<section>
<h2>3. sticky: 이 영역 안에서 스크롤</h2>
<p id="scroll-help">
실패 제목은 top이 없어 함께 사라집니다. 수정 제목은 위에 붙습니다. 아래 영역에
초점을 두고 방향키로도 스크롤할 수 있습니다.
</p>
<div
class="scroll-lab"
tabindex="0"
role="region"
aria-label="Sticky 스크롤 실험"
aria-describedby="scroll-help"
>
<div class="sticky-content">
<h3 class="sticky-broken">실패 · top 없음</h3>
<h3 class="sticky-fixed">수정 · top: 0</h3>
<p>스크롤 시작: 수정 제목이 영역 상단에 도착하는 순간을 보세요.</p>
<p class="scroll-space">
긴 본문 구간입니다. 스크롤해도 제목은 이 스크롤 영역을 기준으로 붙습니다.
</p>
<p>본문 끝: sticky는 자신의 컨테이너 경계를 무한히 벗어나지 않습니다.</p>
</div>
</div>
</section>
<section>
<h2>4. fixed: 문서 스크롤로 확인</h2>
<p>
이 문단까지 문서 전체를 스크롤해 보세요. 상단 링크는 화면 위에 남습니다. 작은
화면에서도 안내가 본문 첫 줄을 가리지 않는지 확인하세요.
</p>
</section>
</main>
</body>
</html>
style.css
* {
box-sizing: border-box;
}
body {
margin: 0;
background: #f4f4f4;
color: #252525;
font-family: system-ui, sans-serif;
line-height: 1.65;
}
main {
width: min(100% - 32px, 880px);
margin: 40px auto;
}
h1 {
font-size: clamp(1.6rem, 4vw, 2.5rem);
line-height: 1.3;
}
h2 {
font-size: 1.25rem;
}
section {
margin-block: 32px;
padding-block: 12px;
border-top: 1px solid #aaa;
}
a {
color: inherit;
text-underline-offset: 4px;
}
a:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
outline: 3px solid #444;
outline-offset: 4px;
}
code {
overflow-wrap: anywhere;
}
.note {
color: #505050;
}
.fixed-bar {
position: fixed;
inset: 0 0 auto;
height: 64px;
display: grid;
place-items: center;
background: #dedede;
z-index: 2;
}
body {
padding-top: 64px;
}
html {
scroll-padding-top: 80px;
}
.flow {
display: flex;
gap: 24px;
padding: 16px;
background: #e1e1e1;
}
.flow span {
padding: 8px;
background: #ccc;
}
.relative-box {
position: relative;
top: 8px;
}
.position-lab {
position: relative;
padding: 56px 16px 16px;
margin-block: 20px;
background: #e6e6e6;
}
.card {
padding: 52px 16px 16px;
background: #fff;
}
.repaired {
position: relative;
}
.badge {
position: absolute;
top: 12px;
right: 12px;
padding: 3px 8px;
background: #444;
color: #fff;
}
.scroll-lab {
height: 300px;
overflow: auto;
background: #e5e5e5;
}
.sticky-content {
padding: 0 16px 20px;
}
.sticky-broken,
.sticky-fixed {
position: sticky;
margin: 0;
padding: 12px;
background: #ccc;
}
.sticky-fixed {
top: 0;
background: #333;
color: #fff;
}
.scroll-space {
min-height: 420px;
padding-block: 40px;
}
완성 CSS 전체 코드
실습 파일과 이어서 읽기
일반적인 화면 배치는 Flex와 미디어 쿼리 반응형 기초, 행과 열의 설계는 CSS Grid 상세 가이드에서 이어서 살펴보세요.
공식 참고 문서
이 글이 도움이 되었나요?
웹 퍼블리싱 학습 순서
필수 13개 · 전체 15개
읽음 기록 관리
전체 과정 목차 (15개)
- 필수 학습 · HTML 입문: 시맨틱 문서와 접근 가능한 폼 만들기
- 필수 학습 · CSS 입문: 박스 모델·선택자·캐스케이드 직접 확인하기
- 필수 학습 · CSS Flex와 미디어 쿼리 입문: 반응형 카드 페이지 만들기
- 필수 학습 · CSS position 완전 이해: relative·absolute·fixed·sticky 실습 현재 글
- 필수 학습 · HTML details와 summary로 접근 가능한 FAQ 만들기
- 필수 학습 · CSS Grid 실습: Flex 학습 카드로 열 맞추기와 auto-fit 비교
- 필수 학습 · CSS overflow 해결: 긴 텍스트·min-width: 0·말줄임 실습
- 필수 학습 · HTML 표 만들기: caption·scope로 비교표를 읽기 쉽게, 모바일에서는 표만 스크롤하기
- 필수 선수 · HTML CSS 이미지 문제 해결 실습: 경로·비율·잘림·흐림·CLS
- 필수 학습 · Container Query 실습: 같은 카드를 본문과 사이드바에 배치하기
- 선택 참고 · CSS Baseline 보는 법: 지원 범위와 폴백을 직접 확인하기
- 필수 학습 · CSS z-index가 안 먹힐 때: stacking context와 부모 층 디버깅
- 필수 선수 · 웹 접근성 기초 점검: 키보드 순서·초점 표시·확대 화면을 직접 확인하는 체크리스트
- 필수 학습 · HTML CSS 종합 실습: 소개·카드·이미지·요금표·문의 폼·FAQ가 있는 반응형 서비스 페이지
- 선택 참고 · 프론트엔드 SEO 기초: HTML 구조와 이미지 성능 진단하기
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.
BlogFlow AI
이 글과 함께 공부하기
무엇을 도와드릴까요?
읽다가 막힌 부분을 물어보세요. 이 글을 바탕으로 설명하고, 이어서 읽을 본문을 연결합니다.