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 zawartości obejmuje jednak nie tylko zapytania dotyczące rozmiaru. umożliwia również wysyłanie zapytań o wartości stylu elementu nadrzędnego. Od Chromium 111 możesz stosować ograniczenia stylu w przypadku wartości właściwości niestandardowych oraz wysyłać zapytania do elementu nadrzędnego w celu uzyskania wartości 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 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 atrybutów i wartości, takich jak 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 następujący kod HTML:

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

Aby używać zapytań dotyczących stylu, 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 elementu nadrzędnego.

Wysyłanie zapytania do bezpośrednich nadrzędnych

Schemat zapytania o styl

W przeciwieństwie do zapytań o styl nie musisz stosować ograniczenia za pomocą właściwości container-type lub container do obiektu .card-container, aby usługa .card mogła wysyłać zapytania o style 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, który określamy w DOM. Nie możemy zastosować stylów, których dotyczy zapytanie, do elementu bezpośredniego, którego styl określamy za pomocą tego zapytania, ponieważ mogłoby to spowodować zapętlenie nieskończoności.

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; 
    ...
  }
}

Jak już możesz zauważyć, zapytanie dotyczące stylu opakowuje zapytanie za pomocą funkcji 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. Parametr min-width może jednak być także właściwością CSS i zapytać o wartość CSS atrybutu min-width, korzystając z zapytań o styl. Dlatego, aby wyraźnie zaznaczyć różnicę, użyj otoczki style(): @container style(min-width: 200px) { … }.

Nadawanie stylów elementom nadrzędnym niebezpośrednim

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 elementu .card na podstawie stylów elementu .card-list, nadając funkcji .card-list atrybut container-name i odwołując się do niego w zapytaniu o styl.

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

Ogólnie rzecz biorąc, warto nadać kontenerom nazwy, aby jasno określić, czego dotyczy zapytanie, i umożliwić im łatwiejszy dostęp do tych kontenerów. Rozwiązanie to przydaje się na przykład wtedy, gdy chcesz bezpośrednio określać styl elementów w interfejsie .card. Jeśli użytkownik nie ma nazwanego kontenera w systemie .card-container, nie może wysyłać do niego zapytań bezpośrednio.

Jednak w praktyce wszystko to ma dużo sens. Przyjrzyjmy się kilku przykładom:

Zapytania dotyczące stylu w praktyce

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 dotyczące stylu są szczególnie przydatne, gdy masz komponent wielokrotnego użytku z wieloma odmianami lub gdy nie masz kontroli nad wszystkimi stylami, ale w określonych przypadkach musisz wprowadzić zmiany. Ten przykład przedstawia zbiór kart produktów, które korzystają z tego samego komponentu 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. Jeśli produkt jest oznaczony jako „Niski poziom w magazynie”, jego tło ma głębokie czerwone obramowanie. 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 --detail i stosować te właściwości niestandardowe CSS, aby stosować 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 do interfejsów --detail: low-stock i --detail: new, ale w bloku kodu można było zauważyć pewną nadmiarowość. 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 dyskutowana przez grupę roboczą.

Karty pogodowe

W poprzednim przykładzie do zastosowania stylów użyliśmy jednej właściwości niestandardowej z wieloma możliwymi wartościami. Możesz też stosować różne kombinacje, korzystając z zapytań dotyczących wielu właściwości niestandardowych. Skorzystaj z przykładowej karty pogody:

Wersja demonstracyjna kart pogodowych.

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

W ten sposób możesz dostosować styl każdej karty do 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 pochmurno i słońce, 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 wersjach oddzielenie warstwy danych (DOM, które byłyby renderowane na stronie) od zastosowanych stylów odznacza się zaletą strukturalną. 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. Jeśli sprawdzisz zarówno --sunny, jak i --cloudy, wykaże to 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):

Dostosuj styl karty, korzystając z zapytań o styl. Kod JavaScript używany do aktualizacji wartości właściwości niestandardowych to:

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 kontenerów pomagają w tworzeniu dynamicznych, elastycznych interfejsów. Jeśli chodzi o zapytania dotyczące stylu, nadal jest kilka nierozwiązanych problemów. Jedna to implementacja zapytań o styl dla 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. Ocena kontekstu wartości logicznych powinna zostać dodana do bieżącego poziomu specyfikacji po rozwiązaniu problemu, a zapytanie dotyczące zakresu jest planowane na kolejnym poziomie specyfikacji.