이 글은 누구를 위한 것인가
- Popper.js, Floating UI 같은 JS 라이브러리를 CSS로 대체하고 싶은 팀
- 복잡한 툴팁 위치 계산 로직을 제거하고 싶은 개발자
- CSS 최신 기능으로 뷰포트 인식 팝오버를 구현하려는 프론트엔드 개발자
들어가며
툴팁 하나를 만드는데 Popper.js 같은 무거운 라이브러리가 필요했다. CSS Anchor Positioning은 이 문제를 CSS만으로 해결한다. 앵커 요소 기준 위치 지정, 뷰포트 벗어남 자동 폴백까지 네이티브로 지원한다.
이 글은 bluefoxdev.kr의 CSS 신기능 실전 가이드 를 참고하여 작성했습니다.
1. Anchor Positioning 핵심 개념
[CSS Anchor Positioning 구조]
앵커 요소: anchor-name 속성으로 이름 지정
위치 요소: position-anchor로 앵커 참조
기본 흐름:
1. 앵커에 이름 부여: anchor-name: --my-button
2. 팝업에 앵커 참조: position-anchor: --my-button
3. 팝업 위치 지정: position-area: top (또는 anchor() 함수)
[position-area 그리드]
9칸 그리드로 위치 지정:
top start | top center | top end
center start| center center | center end
bottom start| bottom center | bottom end
[anchor() 함수]
top: anchor(bottom) → 앵커 아래에 배치
left: anchor(right) → 앵커 오른쪽에 배치
정밀한 오프셋 계산 가능
[@position-try]
뷰포트 벗어날 때 대체 위치 자동 시도
Popper.js의 flip 기능을 CSS로 구현
2. CSS Anchor Positioning 구현
/* 기본 툴팁 */
.button {
anchor-name: --tooltip-anchor;
position: relative;
}
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
/* 앵커 위쪽 중앙 배치 */
position-area: top center;
/* 앵커에서 8px 떨어지게 */
margin-bottom: 8px;
/* 스타일 */
background: #1a1a2e;
color: white;
padding: 6px 12px;
border-radius: 6px;
font-size: 14px;
white-space: nowrap;
/* 기본적으로 숨김 */
opacity: 0;
transition: opacity 0.2s;
}
/* 버튼 호버 시 툴팁 표시 */
.button:hover + .tooltip,
.button:focus + .tooltip {
opacity: 1;
}
/* 뷰포트 벗어남 자동 처리 */
@position-try --flip-bottom {
position-area: bottom center;
margin-top: 8px;
margin-bottom: 0;
}
@position-try --flip-right {
position-area: right center;
margin-left: 8px;
margin-bottom: 0;
}
.tooltip {
position-try-fallbacks: --flip-bottom, --flip-right;
}
/* 툴팁 화살표 */
.tooltip::before {
content: '';
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #1a1a2e;
border-bottom: none;
}
/* Popover API + Anchor Positioning 결합 */
/* 더보기 메뉴 버튼 */
.menu-trigger {
anchor-name: --menu-anchor;
}
/* Popover (HTML popover 속성 필수) */
.dropdown-menu {
position: absolute;
position-anchor: --menu-anchor;
position-area: bottom end;
margin-top: 4px;
/* Popover 기본 스타일 초기화 */
border: none;
padding: 0;
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
min-width: 160px;
/* Popover 표시/숨김 애니메이션 */
opacity: 0;
transform: translateY(-4px);
transition: opacity 0.15s, transform 0.15s, display 0.15s allow-discrete;
}
.dropdown-menu:popover-open {
opacity: 1;
transform: translateY(0);
}
@starting-style {
.dropdown-menu:popover-open {
opacity: 0;
transform: translateY(-4px);
}
}
/* 뷰포트 오른쪽 끝 처리 */
@position-try --align-left {
position-area: bottom start;
}
.dropdown-menu {
position-try-fallbacks: --align-left;
}
<!-- HTML 구조 -->
<button
class="menu-trigger"
popovertarget="user-menu"
>
내 계정 ▾
</button>
<menu
id="user-menu"
class="dropdown-menu"
popover
>
<li><a href="/profile">프로필</a></li>
<li><a href="/settings">설정</a></li>
<li>
<button popovertarget="user-menu" popovertargetaction="hide">
로그아웃
</button>
</li>
</menu>
<!-- 툴팁 -->
<button class="button" type="button">
저장
</button>
<div class="tooltip" role="tooltip">
Ctrl+S로도 저장할 수 있습니다
</div>
<!-- 고급: aria 연결 -->
<button
class="button"
type="button"
aria-describedby="save-tooltip"
>
저장
</button>
<div id="save-tooltip" class="tooltip" role="tooltip">
변경사항이 자동 저장됩니다
</div>
/* position-area 전체 옵션 시각화 */
/* 수직 배치 */
.popup { position-area: top; } /* 위 */
.popup { position-area: bottom; } /* 아래 */
/* 수평 배치 */
.popup { position-area: left; } /* 왼쪽 */
.popup { position-area: right; } /* 오른쪽 */
/* 모서리 배치 */
.popup { position-area: top left; }
.popup { position-area: top right; }
.popup { position-area: bottom left; }
.popup { position-area: bottom right; }
/* 정렬 조합 */
.popup { position-area: top span-all; } /* 위쪽, 앵커 전체 너비 */
.popup { position-area: bottom center; } /* 아래쪽 중앙 */
/* anchor() 함수 (세밀한 제어) */
.popup {
top: anchor(bottom); /* 앵커 하단에 붙임 */
left: anchor(center); /* 앵커 중앙 정렬 */
transform: translateX(-50%);
}
/* 브라우저 지원 확인 */
@supports (anchor-name: --test) {
/* Anchor Positioning 지원 */
.tooltip { position: absolute; }
}
@supports not (anchor-name: --test) {
/* 폴백: JavaScript 기반 툴팁 */
.tooltip { display: none; }
}
마무리
CSS Anchor Positioning은 Popper.js, Floating UI의 JS 의존성을 제거할 수 있는 강력한 대안이다. position-area로 9방향 배치, @position-try로 뷰포트 인식 폴백, Popover API와 결합하면 JS 없이 접근성 높은 드롭다운/툴팁을 만들 수 있다. 2026년 기준 Chrome, Edge, Firefox 최신 버전에서 지원되며, Safari도 지원이 추가됐다. @supports로 점진적 향상을 적용하면 구형 브라우저에서도 안전하다.