Pierwsze kroki z zapytaniami dotyczącymi stylu

Możliwość wysyłania zapytań dotyczących rozmiaru wbudowanego elementu nadrzędnego i wartości jednostek zapytań kontenera jest ostatnio obsługiwana przez wszystkie nowoczesne silniki przeglądarek.

Obsługa przeglądarek

  • 105
  • 105
  • 110
  • 16

Źródło

Specyfikacja zawartości obejmuje jednak nie tylko zapytania dotyczące rozmiaru. Umożliwia też wykonywanie 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

  • 111
  • 111
  • x
  • x

Źródło

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

Specyfikacja modułu zawartości CSS poziomu 3, która obejmuje zapytania dotyczące rozmiaru i stylu, umożliwia pobieranie dowolnych stylów z elementu nadrzędnego, w tym par właściwości i wartości, takich jak font-weight: 800. Jednak podczas wdrażania tej funkcji zapytania dotyczące stylu działają obecnie tylko z wartościami właściwości niestandardowych CSS. Przydaje się to do łączenia stylów i oddzielania danych od projektu. Zobaczmy, jak używać zapytań o styl z niestandardowymi 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 zapytanie dotyczy bezpośredniego, czy pośredniego rodzica.

Wysyłanie zapytań dotyczących bezpośrednich elementów nadrzędnych

Schemat zapytania dotyczącego stylu.

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 wysłać zapytanie bezpośrednio do 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(). Pozwala ona rozróżnić wartości rozmiaru ze stylów. Możesz na przykład wpisać zapytanie o szerokość kontenera jako @container (min-width: 200px) { … }. W ten sposób zastosowano style, jeśli kontener nadrzędny ma szerokość co najmniej 200 pikseli. 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 właśnie należy użyć kodu style(), aby wyraźnie podkreślić różnicę: @container style(min-width: 200px) { … }.

Ustawianie stylu elementów nadrzędnych niebezpośrednich

Jeśli chcesz wysyłać zapytania dotyczące stylów dowolnego elementu, który nie jest bezpośrednim elementem nadrzędnym, musisz mu nadać 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

Obraz demonstracyjny z kilkoma kartami produktów, niektórymi z tagami „nowy” lub „niski asortyment” oraz kartą „niska ilość towaru” na czerwonym tle.

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 uwagi, np. „Nowy” lub „Mało w magazynie”, 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. Informacje tego typu są prawdopodobnie renderowane przez serwer i można je zastosować do kart za pomocą stylów wbudowanych, takich jak:

 <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 danym uporządkowanym możesz przekazywać wartości do funkcji --detail i używać tej właściwości niestandardowej CSS do stosowania stylów:

@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 wysyłać zapytań tylko o obecność elementu --detail w elemencie @container style(--detail), co pozwoliłoby poprawić udostępnianie stylów i zmniejszyć liczbę 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 to jednak mylić, używając wielu właściwości niestandardowych i wysyłając dotyczących ich zapytania. Skorzystaj z przykładowej karty pogody:

Wersja demonstracyjna kart pogodowych.

Aby określić styl gradientów tła i ikon na tych kartach, poszukaj charakterystyki pogody, np. „pochmurnie”, „deszcz” lub „słoneczny”:

@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ż zmieniać styl kombinacji cech charakterystycznych (właściwość niestandardowa), korzystając z kombinatora and w taki sam sposób, jak w przypadku zapytań o media. 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;
  }
}

Oddzielenie danych od projektu

W obu tych wersjach oddzielenie warstwy danych (DOM, który byłby renderowany na stronie) od zastosowanych stylów odznacza się zaletą strukturalną. Style są zapisywane jako możliwe warianty znajdujące się w obrębie stylu komponentu, a punkt końcowy może wysyłać dane, które posłużą do określenia stylu komponentu. Możesz użyć jednej wartości, np. w pierwszym przypadku, zaktualizować wartość --detail, lub wielu zmiennych, np. w drugim przypadku (ustawienie --rainy, --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 właściwości niestandardowych można aktualizować za pomocą JavaScriptu podczas konfigurowania modelu DOM (np. podczas tworzenia komponentu w ramach platformy) lub w dowolnym momencie za pomocą narzędzia <parentElem>.style.setProperty('--myProperty’, <value>). I

Oto demonstracja, która w kilku wierszach kodu aktualizuje --theme przycisku oraz stosuje style za pomocą zapytań o styl 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. Ta funkcja jest już częścią obecnego poziomu 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.