시맨틱 구성요소 적응

스타일 쿼리 (@container style())를 사용하여 각 컨텍스트를 생성하거나 반응하는 항목을 하드코딩하지 않고도 컨텍스트 변형을 트리거합니다. 이렇게 하면 디자인 시스템 결합이 줄어들고 확장성과 구성요소 캡슐화가 개선됩니다.

예를 들어 section.featured { --surface: featured } 규칙은 컨텍스트를 표시할 수 있으며 방문 페이지도 main { --surface: featured }를 통해 기본값으로 설정될 수 있습니다. 그러면 구성요소는 --surface: featured에 반응하도록 선택합니다. 카드는 프로모션 배지를 표시하고 버튼은 기본적으로 채워진 변형으로 설정됩니다.

스타일 쿼리를 사용하면 양쪽이 분리된 상태를 유지할 수 있습니다. 추천 표시 경로에서는 이에 맞게 조정되는 요소의 이름을 지정하지 않으며 구성요소는 컨텍스트를 생성한 항목을 검사하지 않습니다. 새로운 구성요소, 새로운 추천 표시 경로 등 어느 쪽이든 다른 쪽에 영향을 주지 않고 독립적으로 확장할 수 있습니다. 하위 선택자 (예: .featured .button)는 반대 상황을 강제합니다. 선택자는 관계의 양쪽을 모두 인코딩해야 하며 어느 한쪽이 변경될 때마다 변경되어야 합니다.

이 가이드를 사용하는 경우

이 가이드에서는 동작 변경사항을 다룹니다. 즉, 배지 숨기기 또는 표시, 레이아웃 방향 전환, 버튼 변형 전환 등 컨텍스트에 따라 렌더링할 항목, 정렬 방법 또는 표시할 변형을 결정하는 구성요소를 다룹니다.

대신 토큰 수준 변경사항(밀도 모드, 테마 또는 여러 구성요소에서 패딩 및 색상과 같은 값을 균일하게 변경하는 기타 상위 토큰)이 필요한 경우 디자인 토큰 반응성을 참고하세요.

적절한 도구 선택

컨텍스트 관계의 양쪽이 독립적으로 변경될 수 있는 경우(새 요소가 컨텍스트를 생성하기 시작하거나 새 구성요소가 컨텍스트에 반응하기 시작할 수 있음) 스타일 쿼리를 사용합니다. 간접 참조는 확장성과 캡슐화에 대한 대가를 지불하며, 스타일 쿼리는 하위 선택자가 할 수 없는 섀도우 DOM 경계를 넘나듭니다. 이러한 유연성이 필요하지 않은 경우 더 간단한 도구를 사용하는 것이 좋습니다.

  • 하위 요소 선택기 (.toolbar .button): 재사용하거나 확장할 수 없는 고정된 일회성 관계입니다. YAGNI가 적용됩니다. 사용하지 않을 간접 참조를 추가하지 마세요.
  • 크기 쿼리 (@container (min-width: …)): 시맨틱 상태가 아닌 사용 가능한 공간에 따라 레이아웃과 밀도가 변경됩니다.
  • 스타일 쿼리 (@container style(…)): 시맨틱 상태 — 구성요소가 특정 컨텍스트에서 렌더링, 정렬 또는 표시해야 하는 항목입니다.

구현 지시문

  1. 컨테이너에서 CSS 맞춤 속성을 사용하여 시맨틱 컨텍스트 플래그를 정의합니다.
  2. 스타일 쿼리에 container-type를 설정하지 마세요. 스타일 쿼리는 가장 가까운 상위 요소에서 상속된 맞춤 속성을 쿼리하며 명시적인 포함 컨텍스트가 필요하지 않습니다.
  3. 필수: @container style(--property: value)를 사용하여 하위 요소에 조건부 스타일을 적용합니다. 스타일 쿼리는 속성이 설정된 요소와 일치할 수 없으며 하위 요소만 일치할 수 있습니다.
  4. 관계가 확장 가능하거나 구성요소/섀도 DOM 경계를 넘나들어야 하는 경우 하위 선택자보다 스타일 쿼리를 사용하세요 (위의 적절한 도구 선택 참고). 하지만 간접 참조가 아무런 이점이 없는 고정된 일회성 관계의 경우 하위 선택자를 유지하세요.

구현 예시

/* 1. Set the context on a layout container */
.featured {
  --surface: featured; /* Semantic context flag for children */
}

/* 2. Component reacts to inherited flag */
.button {
  /* Default: Outlined informational style */
  background: transparent;
  border: 1px solid currentColor;
}

.badge {
  /* Default: Hidden — only revealed in featured surfaces */
  display: none;
}

@container style(--surface: featured) {
  .button {
    /* Automatic switch to Filled promotional style */
    background: var(--brand-accent);
    color: white;
    border: none;
  }

  .badge {
    /* Reveal decorative elements only in featured context */
    display: block;
  }
}

대체 전략

컨테이너 스타일 쿼리가 널리 사용될 때까지 점진적 개선으로 레이어링합니다. 어디서나 작동하는 선택기 기반 기본값을 제공하고 지원되는 경우 스타일 쿼리가 이를 재정의하도록 합니다. 컨텍스트 선택기에 :where()를 사용하면 스타일 쿼리 (동일한 특수성, 소스 순서에서 나중)가 자동으로 적용됩니다.

/* Default styles — work everywhere */
.button {
  background: transparent;
  border: 1px solid currentColor;
}

.badge {
  display: none;
}

/* Selector-based contextual styles — broad browser support */
:where(.featured) .button {
  background: var(--brand-accent);
  color: white;
  border: none;
}

:where(.featured) .badge {
  display: block;
}

/* Progressive enhancement: style queries override when supported */
@container style(--surface: featured) {
  .button {
    background: var(--brand-accent);
    color: white;
    border: none;
  }

  .badge {
    display: block;
  }
}

선택기 대체는 문맥 스타일을 클래스 이름에 연결하여 구성요소를 DOM 배치에 결합합니다. 스타일 쿼리가 널리 지원되면 :where() 규칙을 삭제할 수 있습니다.