CSS @scope와 Anchor Positioning: 2026년 레이아웃의 두 가지 혁신 실전 가이드

CSS가 스스로 경계를 그을 수 있다면
2026년 프론트엔드 생태계에서 두 가지 CSS 기능이 조용하지만 확실하게 실무의 판도를 바꾸고 있습니다. @scope와 Anchor Positioning입니다. 두 기능은 서로 다른 문제를 풀지만, 공통적으로 "자바스크립트가 처리하던 일을 CSS가 직접 처리한다"는 흐름 위에 있습니다.
@scope는 스타일 격리 문제를 해결합니다. Anchor Positioning은 팝오버, 툴팁, 드롭다운의 위치 계산 문제를 해결합니다. 두 기능 모두 2026년 기준 Chromium 기반 브라우저에서 안정적으로 동작하며, 점진적 적용 전략도 충분히 실현 가능합니다.
1. @scope의 탄생 배경: CSS 격리의 새 접근
| 방법 | 격리 수준 | 빌드 도구 의존 | JS 런타임 비용 | 단점 |
|---|---|---|---|---|
| CSS Modules | 높음 | 필요 | 없음 | 빌드 설정 필요 |
| Shadow DOM | 완전 격리 | 불필요 | 있음 | 외부 스타일 차단 |
| BEM 네이밍 | 규약 의존 | 불필요 | 없음 | 사람 실수 의존 |
| styled-components | 높음 | 필요 | 있음 | SSR hydration 비용 |
| @scope | 명시적 범위 | 불필요 | 없음 | 브라우저 지원 제한 |
CSS Cascade 6 스펙에서 정의된 @scope는 스타일을 "어디에 적용할지"가 아니라 "어디서부터 어디까지 영향을 미칠지"를 CSS 선언 안에서 명시합니다.
@scope는 "Proximity(근접성)"라는 새로운 카스케이드 기준을 도입합니다. 같은 명시도의 규칙이 충돌할 때, 타겟 요소와 더 가까운 스코프에 속한 규칙이 이깁니다. 이 개념이 기존의 명시도·출처 순서와 어떻게 상호작용하는지는 CSS @layer 실전 가이드에서 다룬 카스케이드 순서와 함께 이해하면 더 명확합니다.
2. :scope 가상 클래스와의 차이
:scope는 CSS 선택자 안에서 현재 스타일 컨텍스트의 루트 요소를 가리키는 가상 클래스입니다. 반면 @scope는 At-rule입니다.
:scope {
--color-brand: #0070f3;
}
@scope (.card) {
img {
border-radius: 0.5rem;
object-fit: cover;
}
p {
color: var(--color-neutral-700);
line-height: 1.6;
}
}
MDN @scope 문서는 이 차이를 명확히 설명합니다. :scope는 선택자 레벨의 가상 클래스이고, @scope는 카스케이드 알고리즘에 근접성 축을 추가하는 At-rule입니다.
@scope 안의 선택자는 스코프 선택자의 명시도를 추가로 가지지 않습니다. 스코프는 명시도가 아니라 근접성으로 우선순위를 결정합니다.
3. 범위 제한과 Donut Scope (from/to 구문)
@scope의 가장 독특한 기능 중 하나는 "구멍이 뚫린 스코프(Donut Scope)"입니다.
@scope (.card) {
h2 {
font-size: 1.25rem;
font-weight: 700;
}
}
/* Donut Scope: .card 안이지만 .card__footer 안은 제외 */
@scope (.card) to (.card__footer) {
p {
color: var(--color-text-primary);
font-size: 0.9375rem;
}
a {
color: var(--color-brand);
text-decoration: underline;
}
}
@scope (.card__footer) {
a {
color: var(--color-text-secondary);
text-decoration: none;
font-size: 0.875rem;
}
}
to 구문에 사용하는 선택자는 스코프 안에 포함되어야 합니다. CSS Container Query와 @scope를 조합하면 컴포넌트가 자신의 공간과 스타일 경계를 모두 자율적으로 관리하는 구조가 완성됩니다.
4. 컴포넌트 스타일 격리 실전 사례
@scope (.feed-card) {
:scope {
display: grid;
grid-template-rows: auto 1fr auto;
gap: 0.75rem;
padding: 1rem;
border: 1px solid var(--color-border);
border-radius: 0.5rem;
}
img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
h3 {
font-size: 1rem;
font-weight: 600;
-webkit-line-clamp: 2;
overflow: hidden;
}
}
@scope (.featured-card) {
:scope {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
padding: 1.5rem;
background: var(--color-surface-elevated);
border-radius: 1rem;
}
img {
width: 100%;
aspect-ratio: 4 / 3;
}
h3 {
font-size: 1.5rem;
font-weight: 700;
}
}
이 패턴의 핵심은 .feed-card img와 .featured-card img가 충돌하지 않는다는 점입니다. @scope를 사용하면 근접성이 우선하므로, 어떤 순서로 선언되든 타겟 요소와 더 가까운 스코프의 규칙이 이깁니다.
5. Anchor Positioning 개념: position-anchor와 anchor()
Anchor Positioning은 한 요소의 위치를 다른 요소(앵커)의 위치에 상대적으로 묶는 CSS 기능입니다. MDN CSS Anchor Positioning 문서는 이를 "하나의 요소가 다른 요소를 위치 기준점으로 삼을 수 있는 메커니즘"이라고 정의합니다.
/* 버튼이 앵커 역할: 이름 부여 */
.dropdown-trigger {
anchor-name: --dropdown-btn;
}
/* 드롭다운 패널: 버튼 아래에 붙도록 위치 */
.dropdown-panel {
position: absolute;
position-anchor: --dropdown-btn;
top: anchor(bottom);
left: anchor(left);
min-width: anchor-size(width);
max-width: 320px;
}
Chrome Developers 블로그의 Anchor Positioning API 소개에 따르면, 이 기능은 position: absolute 또는 position: fixed를 사용하는 요소에서만 동작합니다.
6. 툴팁·드롭다운·팝오버 구현 패턴
.tooltip-btn {
anchor-name: --tooltip-anchor;
position: relative;
}
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
bottom: calc(anchor(top) + 8px);
left: anchor(center);
transform: translateX(-50%);
background: var(--color-neutral-900);
color: white;
padding: 0.375rem 0.625rem;
border-radius: 0.375rem;
font-size: 0.8125rem;
white-space: nowrap;
pointer-events: none;
opacity: 0;
visibility: hidden;
transition: opacity 150ms ease, visibility 150ms ease;
}
.tooltip-btn:hover + .tooltip,
.tooltip-btn:focus-visible + .tooltip {
opacity: 1;
visibility: visible;
}
<button popovertarget="user-menu" class="user-btn">계정 메뉴</button>
<div id="user-menu" popover class="user-popover">
<ul>
<li><a href="/profile">프로필 설정</a></li>
<li><a href="/billing">결제 관리</a></li>
<li><button>로그아웃</button></li>
</ul>
</div>
.user-btn {
anchor-name: --user-menu-anchor;
}
.user-popover {
position: absolute;
position-anchor: --user-menu-anchor;
top: anchor(bottom);
right: anchor(right);
margin-top: 0.5rem;
min-width: 200px;
background: var(--color-surface);
border-radius: 0.5rem;
box-shadow: var(--shadow-md);
}
popover API와 함께 사용하면 키보드 트랩, Escape 키로 닫기, ARIA 속성을 브라우저에서 자동으로 처리합니다.
7. @position-try fallback 전략
.tooltip {
position: absolute;
position-anchor: --my-anchor;
top: calc(anchor(bottom) + 8px);
left: anchor(center);
transform: translateX(-50%);
position-try-fallbacks:
--tooltip-above,
--tooltip-left,
--tooltip-right;
}
@position-try --tooltip-above {
top: auto;
bottom: calc(anchor(top) + 8px);
}
@position-try --tooltip-left {
top: anchor(center);
transform: translateY(-50%);
left: auto;
right: calc(anchor(left) + 8px);
}
@position-try --tooltip-right {
top: anchor(center);
transform: translateY(-50%);
left: calc(anchor(right) + 8px);
}
브라우저는 기본 위치를 먼저 시도합니다. 해당 위치로 렌더링했을 때 팝오버가 viewport를 벗어나면, position-try-fallbacks 목록을 순서대로 시도합니다.
8. 브라우저 지원 현황과 polyfill 옵션
@scope 지원 현황: Chrome 118+, Edge 118+, Firefox 128+, Safari 17.4+. 모든 주요 브라우저에서 지원하는 Baseline Newly Available 기능입니다.
Anchor Positioning 지원 현황: Chrome 125+, Edge 125+, Firefox 133+ (일부 플래그). Safari는 미지원(개발 중).
.tooltip {
position: fixed;
top: var(--tooltip-top, 0);
left: var(--tooltip-left, 0);
}
@supports (anchor-name: --test) {
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
top: calc(anchor(bottom) + 8px);
left: anchor(center);
transform: translateX(-50%);
}
}
9. 기존 JavaScript 포지셔닝(Floating UI) 대체 가능성
| 기능 | Floating UI | CSS Anchor Positioning |
|---|---|---|
| 기본 위치 지정 | 지원 | 지원 |
| Viewport 감지 fallback | 지원 | @position-try로 지원 |
| 화살표(꼬리) 위치 계산 | 지원 | 수동 계산 필요 |
| 가상 요소 앵커 | 지원 | 미지원 |
| Safari 지원 | 지원 | 미지원 |
| 번들 크기 | ~10KB | 0KB |
| 스크롤 추적 자동화 | JS 이벤트 | 브라우저 내장 |
현재 권장하는 전략은 @supports 기반 점진적 적용입니다. Chromium 기반 브라우저에서는 CSS 방식으로, Safari 등 미지원 브라우저에서는 Floating UI로 처리합니다.
10. 디자인 시스템 적용 체크리스트
@scope 도입 체크리스트
- 컴포넌트 경계를 어떤 선택자를 스코프 루트로 사용할지 결정했는가
@layer와 함께 사용할 때 레이어 안에@scope를 중첩하는 방식으로 우선순위를 관리하고 있는가- Donut Scope(
to구문)가 필요한 중첩 컴포넌트를 식별했는가
Anchor Positioning 도입 체크리스트
- 대상 컴포넌트(툴팁, 드롭다운, 팝오버, 컨텍스트 메뉴)를 목록화했는가
@supports (anchor-name: --test)감지로 미지원 브라우저에 Floating UI fallback을 준비했는가@position-tryfallback 전략이 4방향(상, 하, 좌, 우)을 모두 커버하는가popoverAPI와 조합해 접근성을 브라우저에 위임했는가
결론
@scope와 Anchor Positioning은 CSS가 "스타일 언어"에서 "UI 레이아웃 로직 언어"로 진화하는 흐름의 두 축입니다.
- 팀의 브라우저 지원 매트릭스를 실제 분석 데이터로 확인하고,
@scope와 Anchor Positioning 각각의 도입 시점을 별도로 결정한다. @scope는@layer구조와 함께 설계한다.- Anchor Positioning 도입 초기에는
popoverAPI와 함께 사용해 접근성 부담을 브라우저에 위임한다. @position-tryfallback을 반드시 작성한다.- Floating UI 같은 기존 JS 포지셔닝 라이브러리를 즉시 제거하지 말고,
@supports감지를 통한 점진적 대체 경로를 설계한다.