Pierwsze kroki z zapytaniami dotyczącymi stylu

Możliwość wysyłania zapytań o rozmiar wstawiony rodzica i wartości jednostek zapytań kontenera została niedawno stabilnie obsługiwana we wszystkich nowoczesnych silnikach przeglądarek.

Obsługa przeglądarek

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 110.
  • Safari: 16.

Źródło

Specyfikacja ograniczeń obejmuje jednak nie tylko zapytania o rozmiary, ale też umożliwia zapytanie o wartości stylu elementu nadrzędnego. W Chromium 111 możesz stosować ograniczanie stylu w przypadku wartości właściwości niestandardowych i zapytać element nadrzędny o wartość właściwości niestandardowej.

Obsługa przeglądarek

  • Chrome: 111.
  • Edge: 111.
  • Firefox: nieobsługiwane.
  • Safari: 18.

Źródło

Oznacza to, że mamy jeszcze większą kontrolę nad stylami w CSS i umożliwia to lepsze oddzielenie logiki aplikacji od jej warstwy danych i stylów.

Specyfikacja modułu CSS Containment Level 3, która obejmuje zapytania o rozmiar i styl, umożliwia wysyłanie zapytań o dowolne style do elementu nadrzędnego, w tym pary właściwości i wartości, np. font-weight: 800. Jednak w ramach wdrażania tej funkcji zapytania dotyczące stylów działają obecnie tylko z wartościami właściwości niestandardowych w CSS. Jest to nadal bardzo przydatne do łączenia stylów i oddzielania danych od projektu. Zobaczmy, jak używać zapytań dotyczących stylów z własnymi właściwościami CSS:

Pierwsze kroki z zapytaniami o styl

Załóżmy, że mamy taki kod HTML:

<ul class="card-list">
  <li class="card-container">
    <div class="card">
      ...
    </div>
  </li>
</ul>

Aby używać zapytań dotyczących stylów, musisz najpierw skonfigurować element kontenera. Wymaga to nieco innego podejścia w zależności od tego, czy wysyłasz zapytanie do bezpośredniego czy pośredniego rodzica.

Wysyłanie zapytania do bezpośrednich nadrzędnych

Schemat zapytania o styl

W przeciwieństwie do zapytań dotyczących stylów nie musisz stosować ograniczeń za pomocą właściwości container-type ani container w .card-container, aby element .card mógł wysyłać zapytania dotyczące stylów swojego bezpośredniego elementu nadrzędnego. Musimy jednak zastosować style (w tym przypadku wartości właściwości niestandardowych) do kontenera (w tym przypadku .card-container) lub dowolnego elementu zawierającego element, do którego stylizujemy w DOM. Nie możemy zastosować stylów, których używamy w zapytaniu do elementu bezpośredniego, do którego stylizujemy za pomocą tego zapytania, ponieważ może to spowodować nieskończone pętle.

Aby bezpośrednio zapytać rodzica, możesz napisać:

/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
  .card {
    background-color: wheat;
    border-color: brown; 
    ...
  }
}

Zauważysz pewnie, że zapytanie dotyczące stylu kończy się znakiem style(). Ma to na celu uniknięcie nieporozumień w przypadku wartości rozmiarów i stylów. Możesz na przykład napisać zapytanie o szerokość kontenera jako @container (min-width: 200px) { … }. Styli można by zastosować, gdyby kontener nadrzędny miał co najmniej 200 pikseli szerokości. Jednak min-width może też być właściwością CSS, a wartość CSS właściwości min-width możesz zapytać za pomocą zapytań o styl. Dlatego, aby wyraźnie zaznaczyć różnicę, użyjesz otoczki style(): @container style(min-width: 200px) { … }.

Formatowanie elementów nadrzędnych niebezpośrednich

Jeśli chcesz wysłać zapytanie o style dotyczące elementu, który nie jest bezpośrednim elementem nadrzędnym, musisz nadać mu wartość container-name. Możemy na przykład zastosować style do .card na podstawie stylów .card-list, nadając .card-list wartość container-name i odwołując się do niej w zapytaniu o styl.

/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
  .card {
    ...
  }
}

Zwykle zaleca się nadawanie kontenerom nazw, aby było jasne, czego dotyczy zapytanie, i ułatwić sobie dostęp do tych kontenerów. Może się to przydać np. wtedy, gdy chcesz nadać styl elementom bezpośrednio w elementach .card. Bez kontenera o nazwie na .card-container nie mogą wysyłać do niego bezpośrednich zapytań.

W praktyce wszystko to ma jednak znacznie więcej sensu. Spójrzmy na kilka przykładów:

Zapytania o styl w działaniu

Ilustracja demonstracyjna z wieloma kartami produktów, niektóre z tagami „nowy” lub „mała ilość w magazynie”, a karta „mała ilość w magazynie” z czerwonym tłem.

Zapytania o style są szczególnie przydatne, gdy masz komponent do wielokrotnego użytku z wieloma wariantami lub gdy nie masz kontroli nad wszystkimi stylami, ale w określonych przypadkach musisz wprowadzić zmiany. Ten przykład pokazuje zestaw kart produktów, które mają ten sam element karty. Niektóre karty produktów zawierają dodatkowe informacje lub notatki, takie jak „Nowość” lub „Mała ilość”, wywoływane przez właściwość niestandardową o nazwie --detail. Dodatkowo, jeśli produkt jest „w magazynie”, ma czerwoną obwódkę. Tego typu informacje są prawdopodobnie renderowane na serwerze i można je stosować do kart za pomocą stylów wbudowanych, np. w ten sposób:

 <div class="product-list">
  <div class="product-card-container" style="--detail: new">
    <div class="product-card">
      <div class="media">
        <img .../>
      <div class="comment-block"></div>
    </div>
  </div>
  <div class="meta">
    ...
  </div>
  </div>
  <div class="product-card-container" style="--detail: low-stock">
    ...
  </div>
  <div class="product-card-container">
    ...
  </div>
  ...
</div>

Dzięki tym uporządkowanym danym możesz przekazywać wartości do właściwości --detail i stosować te właściwości niestandardowe CSS, aby zastosować style:

@container style(--detail: new) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'New';
    border: 1px solid currentColor;
    background: white;
    ...
  }
}

@container style(--detail: low-stock) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'Low Stock';
    border: 1px solid currentColor;
    background: white;
    ...
  }
  
  .media-img {
    border: 2px solid brickred;
  }
}

Powyższy kod pozwala nam zastosować element --detail: low-stock--detail: new, ale być może zauważysz pewną nadmiarowość w bloku kodu. Obecnie nie można zapytać o tylko obecność --detail w przypadku @container style(--detail), co pozwoliłoby na lepsze udostępnianie stylów i mniej powtórzeń. Ta funkcja jest obecnie omawiana w grupie roboczej.

Karty pogody

W poprzednim przykładzie do zastosowania stylów użyto jednej właściwości niestandardowej z wieloma możliwymi wartościami. Możesz też stosować różne metody, korzystając z zapytań dotyczących wielu właściwości niestandardowych. Weźmy na przykład kartę pogody:

Demonstracja kart pogody.

Aby nadać styl gradientom tła i ikonom na tych kartach, poszukaj informacji o warunkach pogodowych, takich jak „chmury”, „deszcz” lub „słonecznie”:

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

Dzięki temu możesz nadać styl każdej karcie na podstawie jej unikalnych cech. Możesz też nadawać stylizacje kombinacjom cech (właściwości niestandardowych) za pomocą operatora and w taki sam sposób jak w przypadku zapytań o multimedia. Na przykład dzień, w którym jest pochmurnie i słonecznie, wygląda tak:

@container style(--sunny: true) and style(--cloudy: true) {
    .weather-card {
      background: linear-gradient(24deg, pink, violet);
    }
  
  .weather-card:after {
      content: url(<data-uri-for-demo-brevity>);
      background: violet;
  }
}

Oddzielanie danych od projektu

W obu tych demonstracjach widać, że rozdzielenie warstwy danych (DOM, która zostanie wyrenderowana na stronie) od zastosowanych stylów przynosi korzyści strukturalne. Style są zapisywane jako możliwe warianty w stylu komponentów, a punkt końcowy może wysyłać dane, których następnie używa do nadawania stylu komponentowi. Możesz użyć pojedynczej wartości, np. w pierwszym przypadku, aktualizując wartość --detail, lub wielu zmiennych, np. w drugim przypadku (ustawiając --rainy lub --cloudy lub --sunny. Najlepsze jest to, że możesz też łączyć te wartości. Sprawdzenie zarówno --sunny, jak i --cloudy może wyświetlić styl częściowo zachmurzony.

Wartości niestandardowych właściwości można aktualizować za pomocą JavaScriptu, np. podczas konfigurowania modelu DOM (czyli podczas tworzenia komponentu w ramach frameworku) lub w dowolnym momencie za pomocą <parentElem>.style.setProperty('--myProperty’, <value>). I

Oto demonstracja, która w kilku wierszach kodu aktualizuje --theme przycisku i zastosowuje style za pomocą zapytań dotyczących stylów i tej właściwości niestandardowej (--theme):

Nadaj karcie styl za pomocą zapytań stylów. Kod JavaScript służący do aktualizowania wartości właściwości niestandardowych:

const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');

themePicker.addEventListener('input', (e) => {
  btnParent.style.setProperty('--theme', e.target.value);
})

Funkcje opisane w tym artykule to dopiero początek. Zapytania dotyczące kontenera mogą Ci pomóc w budowaniu dynamicznych, responsywnych interfejsów. W przypadku zapytań dotyczących stylu wciąż występuje kilka otwartych problemów. Jednym z nich jest implementacja zapytań dotyczących stylów CSS poza właściwościami niestandardowymi. Jest to już część bieżącej specyfikacji, ale nie została jeszcze zaimplementowana w żadnej przeglądarce. Oczekujemy, że weryfikacja kontekstu logicznego zostanie dodana do obecnego poziomu specyfikacji, gdy nierozwiązany problem zostanie rozwiązany, a zapytanie o zakres zostanie zaplanowane na kolejnym poziomie specyfikacji.