Dostosowywanie komponentów semantycznych

Funkcje internetowe: Zapytania o styl kontenera

Używaj zapytań o style (@container style()), aby aktywować odmiany kontekstowe bez kodowania na stałe tego, co generuje dany kontekst lub na niego reaguje. Zmniejsza to powiązanie systemu projektowania i poprawia rozszerzalność oraz hermetyzację komponentów.

Na przykład reguła section.featured { --surface: featured } może oznaczać kontekst, a strona docelowa może też domyślnie używać go za pomocą main { --surface: featured }. Komponenty mogą reagować na --surface: featured: na karcie pojawia się plakietka promocyjna, przycisk domyślnie zmienia się na wypełniony itd.

Zapytania o style pozwalają obu stronom zachować niezależność: polecane powierzchnie nigdy nie nazywają elementów, które się do nich dostosowują, a komponenty nigdy nie sprawdzają, co wygenerowało kontekst. Każdą stronę można rozszerzać niezależnie – nowe komponenty, nowe polecane platformy – bez wpływu na drugą stronę. Selektory potomne (np. .featured .button) wymuszają odwrotne działanie: selektor musi kodować obie strony relacji i musi się zmieniać, gdy zmienia się dowolna z nich.

Kiedy korzystać z tego przewodnika

Ten przewodnik dotyczy zmian behawioralnych: komponent decyduje, co renderować, jak się ułożyć lub który wariant zaprezentować w odpowiedzi na kontekst – ukrywa lub pokazuje plakietkę, zmienia kierunek układu lub zamienia wariant przycisku.

Jeśli potrzebujesz zmian na poziomie tokenów – trybów gęstości, motywów lub innych tokenów wyższego rzędu, które jednolicie zmieniają wartości, takie jak dopełnienie i kolor, w wielu komponentach – zapoznaj się z artykułem Reaktywność tokenów projektowych.

Wybór odpowiedniego narzędzia

Zapytanie o styl warto zastosować, gdy obie strony relacji kontekstowej mogą zmieniać się niezależnie – nowe elementy mogą zacząć tworzyć kontekst lub nowe komponenty mogą zacząć na niego reagować. Pośredniość opłaca się pod względem rozszerzalności i enkapsulacji, a zapytania o styl przekraczają granice modelu Shadow DOM, czego nie mogą zrobić selektory potomne. Jeśli nie potrzebujesz takiej elastyczności, wybierz prostsze narzędzie:

  • Selektory potomne (.toolbar .button): stała, jednorazowa relacja, której nie można ponownie wykorzystać ani rozszerzyć. Zastosuj zasadę YAGNI – nie dodawaj pośrednictwa, którego nie będziesz używać.
  • Zapytania o rozmiar (@container (min-width: …)): zmiany układu i gęstości wynikające z dostępnego miejsca, a nie stanu semantycznego.
  • Zapytania o styl (@container style(…)): stan semantyczny – co komponent powinien renderować, rozmieszczać lub prezentować w danym kontekście.

Dyrektywy dotyczące implementacji

  1. Zdefiniuj flagę kontekstu semantycznego za pomocą właściwości niestandardowej CSS w kontenerze.
  2. NIE ustawiaj właściwości container-type w przypadku zapytań o style. Odpytują one odziedziczone właściwości niestandardowe najbliższego elementu nadrzędnego i nie wymagają wyraźnego kontekstu kontenera.
  3. OBOWIĄZKOWO: użyj @container style(--property: value), aby zastosować style warunkowe do elementów podrzędnych. Zapytania o style nie mogą pasować do elementu, dla którego ustawiono właściwość, a jedynie do jego elementów podrzędnych.
  4. ZALECAMY preferowanie zapytań o styl nad selektorami potomnymi, gdy relacja musi być rozszerzalna lub przekraczać granice komponentu/shadow DOM (patrz Wybór odpowiedniego narzędzia powyżej) – ale zachowaj selektory potomne w przypadku stałych, jednorazowych relacji, w których pośrednictwo nic nie daje.

Przykład wdrożenia

/* 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;
  }
}

Strategie zastępcze

Dopóki zapytania o styl kontenera nie będą powszechnie dostępne, nakładaj je jako progresywne ulepszanie: dostarczaj domyślne zapytanie oparte na selektorze, które działa wszędzie, i pozwól, aby zapytanie o styl je zastępowało, gdy jest obsługiwane. Użyj :where() w selektorze kontekstu, aby zapytanie o styl (ta sama specyficzność, później w kolejności źródłowej) wygrało automatycznie.

/* 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;
  }
}

Selektor zastępczy wiąże styl kontekstowy z nazwą klasy, co łączy komponent z jego miejscem w DOM. Gdy zapytania o style będą powszechnie obsługiwane, regułę :where() będzie można usunąć.