기존에는 @container 규칙을 쓸 때 조건(query)이 필수라고 인식하는 경우가 많았지만, 스펙 상 <container-name>과 <container-query> 중 하나 이상만 있으면 됩니다.
즉, 쿼리 조건 없이 컨테이너 이름만으로도 @container 블록을 선언할 수 있습니다.
문법 구조
@container [<container-name>]? [<container-query>]? { ... }| 형태 | 예시 | 의미 |
|---|---|---|
| 조건만 | @container (width > 400px) | 가장 가까운 컨테이너의 크기 조건 |
| 이름 + 조건 | @container sidebar (width > 400px) | sidebar 컨테이너의 크기 조건 |
| 이름만 | @container sidebar | sidebar 컨테이너 안에 있을 때 |
| 조건 리스트 | @container (조건A), style(--x: y) | 여러 조건 중 하나라도 참이면 |
예시 코드
기본 — 이름만으로 스코핑
/* 컨테이너 선언 */header { container: header / inline-size; }.sidebar { container: sidebar / inline-size; }main { container: main / inline-size; }footer { container: footer / inline-size; }
/* 이름만으로 스코핑 — 크기 조건 없이 컨텍스트만으로 분기 */@container sidebar { .card { font-size: .875rem; flex-direction: column; }}
@container main { .card { font-size: 1rem; display: grid; }}
@container footer { .card { display: none; }}이름 + 크기 조건 조합
/* sidebar 안에서 + 너비 조건 추가 */@container sidebar (width > 240px) { .card { flex-direction: row; }}
/* main 안에서 + 너비 조건 추가 */@container main (width > 600px) { .card { grid-template-columns: repeat(3, 1fr); }}조건 리스트 (OR 동작)
/* 쉼표로 구분 — 하나라도 true면 적용 */@container card (width > 400px), style(--responsive: true), scroll-state(stuck: top) { h2 { font-size: 1.5em; }}왜 유용한가?
컴포넌트 재사용 — “컨텍스트 네임스페이스”
같은 .card 컴포넌트 하나를 만들어두면, 어느 컨테이너 안에 놓이느냐에 따라 자동으로 다른 스타일이 적용됩니다.
/* before — 영역별로 클래스를 따로 만들어야 했음 */ .sidebar__card { ... } .main__card { ... } .footer__card { ... }
/* after — 컴포넌트 하나 + @container 이름 스코핑 */ .card { ... } /* 하나만 */ @container sidebar { .card { ... } } @container main { .card { ... } }크기를 몰라도 되는 경우
너비/높이 조건 없이 “이 레이아웃 영역 안에 있다”는 사실 자체만으로 스타일을 분기해야 할 때 유용합니다.
예: sidebar는 항상 compact, footer는 항상 숨김 등
브라우저 지원
/* 지원 여부 확인 후 적용 */@supports (container-type: inline-size) { header { container: header / inline-size; }}MDN 참고 예시
/* With a <size-query> */@container (width > 400px) { h2 { font-size: 1.5em; } }
/* With an optional <container-name> */@container tall (height > 30rem) { p { line-height: 1.6; } }
/* With a <container-name> only (query is optional) */@container sidebar { h2 { background: blue; } }
/* With a <scroll-state> */@container scroll-state(scrollable: top) { .back-to-top-link { visibility: visible; }}
/* Multiple queries in a single condition */@container (width > 400px) and style(--responsive: true) { h2 { font-size: 1.5em; }}
/* Condition list */@container card (width > 400px), style(--responsive: true), scroll-state(stuck: top) { h2 { font-size: 1.5em; }}