Pierwsze kroki z zapytaniami dotyczącymi stylu

Możliwość wysyłania zapytań o rozmiar wbudowany elementu nadrzędnego i wartości jednostek zapytań o kontener osiągnęła niedawno stabilną obsługę we wszystkich nowoczesnych silnikach przeglądarek.

Browser Support

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

Source

Specyfikacja containment obejmuje jednak nie tylko zapytania o rozmiar, ale też umożliwia wysyłanie zapytań o wartości stylu elementu nadrzędnego. Od Chromium 111 będzie można stosować containment stylu w przypadku wartości właściwości niestandardowych i wysyłać zapytania do elementu nadrzędnego o wartość właściwości niestandardowej.

Browser Support

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 151.
  • Safari: 18.

Oznacza to, że mamy jeszcze większą kontrolę logiczną nad stylami w CSS i możemy lepiej oddzielić logikę aplikacji i warstwę danych od jej stylów.

Specyfikacja CSS Containment Module Level 3, która obejmuje zapytania o rozmiar i styl, umożliwia wysyłanie zapytań do elementu nadrzędnego o dowolne style, w tym pary właściwości i wartości, takie jak font-weight: 800. Jednak w przypadku wdrażania tej funkcji zapytania o styl działają obecnie tylko z wartościami właściwości niestandardowych CSS. Jest to nadal bardzo przydatne do łączenia stylów i oddzielania danych od projektu. Zobaczmy, jak używać zapytań o styl z właściwościami niestandardowymi 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ń o styl, musisz najpierw skonfigurować element kontenera. Wymaga to nieco innego podejścia w zależności od tego, czy wysyłasz zapytanie do elementu nadrzędnego bezpośredniego czy pośredniego.

Wysyłanie zapytań do elementów nadrzędnych bezpośrednich

Diagram zapytania o styl.

W przeciwieństwie do zapytań o styl nie musisz stosować containment za pomocą właściwości container-type ani container do elementu .card-container, aby element .card mógł wysyłać zapytania o style swojego elementu nadrzędnego bezpośredniego. 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 stylizujemy w DOM. Nie możemy stosować stylów, o które wysyłamy zapytanie, do elementu bezpośredniego, który stylizujemy za pomocą tego zapytania, ponieważ może to spowodować nieskończone pętle.

Aby bezpośrednio wysłać zapytanie do elementu nadrzędnego, 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; 
    ...
  }
}

Możesz zauważyć, że zapytanie o styl otacza zapytanie za pomocą style(). Ma to na celu odróżnienie wartości rozmiaru od stylów. Możesz na przykład napisać zapytanie o szerokość kontenera w postaci @container (min-width: 200px) { … }. Spowoduje to zastosowanie stylów, jeśli szerokość kontenera nadrzędnego będzie wynosić co najmniej 200 pikseli. Jednak min-width może być też właściwością CSS, a za pomocą zapytań o styl możesz wysyłać zapytania o wartość CSS właściwości min-width. Dlatego używasz otoczki style(), aby wyraźnie zaznaczyć różnicę: @container style(min-width: 200px) { … }.

Stylizowanie elementów nadrzędnych niebezpośrednich

Jeśli chcesz wysyłać zapytania o style dowolnego elementu, który nie jest elementem nadrzędnym bezpośrednim, musisz nadać mu container-name. Możemy na przykład zastosować style do elementu .card na podstawie stylów elementu .card-list, nadając elementowi .card-list nazwę 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 {
    ...
  }
}

Ogólnie zaleca się nadawanie nazw kontenerom, aby było jasne, o co wysyłasz zapytanie, i aby ułatwić dostęp do tych kontenerów. Przykładem, w którym może się to przydać, jest sytuacja, gdy chcesz bezpośrednio stylizować elementy w obrębie elementu .card. Bez nazwanego kontenera w elemencie .card-container nie mogą one bezpośrednio wysyłać do niego zapytań.

Jednak w praktyce ma to o wiele więcej sensu. Przyjrzyjmy się kilku przykładom:

Zapytania o styl w praktyce

Obraz demonstracyjny z wieloma kartami produktów, niektóre z tagami „nowość” lub „mała ilość”, a karta „mała ilość” z czerwonym tłem.

Zapytania o styl są szczególnie przydatne, gdy masz komponent wielokrotnego użytku z wieloma wariantami lub gdy nie masz kontroli nad wszystkimi stylami, ale w niektórych przypadkach musisz wprowadzić zmiany. Ten przykład przedstawia zestaw kart produktów, które mają ten sam komponent karty. Niektóre karty produktów zawierają dodatkowe szczegóły lub uwagi, np. „Nowy” lub „Mała ilość”, wywoływane przez właściwość niestandardową o nazwie --detail. Jeśli produkt ma „Małą ilość”, otrzymuje też ciemnoczerwone tło obramowania. Tego typu informacje są prawdopodobnie renderowane po stronie serwera i można je stosować do kart za pomocą stylów wbudowanych 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>

Na podstawie tych uporządkowanych danych możesz przekazywać wartości do --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 umożliwia stosowanie etykiety dla --detail: low-stock i --detail: new, ale możesz zauważyć pewną nadmiarowość w bloku kodu. Obecnie nie można wysyłać zapytań o samą obecność --detail za pomocą @container style(--detail), co pozwoliłoby na lepsze udostępnianie stylów i mniejsze powtórzenia. Ta funkcja jest obecnie omawiana w grupie roboczej.

Karty pogodowe

W poprzednim przykładzie do stosowania stylów użyto jednej właściwości niestandardowej z wieloma możliwymi wartościami. Możesz jednak mieszać style, używając wielu właściwości niestandardowych i wysyłając do nich zapytania. Oto przykład karty pogodowej:

Prezentacja kart pogodowych.

Aby stylizować gradienty tła i ikony tych kart, wyszukaj cechy pogody, takie jak „pochmurno”, „deszczowo” 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 stylizować każdą kartę na podstawie jej unikalnych cech. Możesz też stylizować kombinacje cech (właściwości niestandardowych), używając kombinatora and w taki sam sposób jak w przypadku zapytań o multimedia. Na przykład dzień, w którym jest zarówno pochmurno, jak i słonecznie, wyglądałby 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 prezentacjach strukturalną zaletą jest oddzielenie warstwy danych (DOM, który będzie renderowany na stronie) od stosowanych stylów. Style są zapisywane jako możliwe warianty, które znajdują się w stylu komponentu, a punkt końcowy może wysyłać dane, które będą następnie używane do stylizowania komponentu. Możesz użyć jednej wartości, tak jak w pierwszym przypadku, aktualizując wartość --detail, lub wielu zmiennych, tak jak w drugim przypadku (ustawiając --rainy, --cloudy lub --sunny). Najlepsze jest to, że możesz też łączyć te wartości. Sprawdzenie zarówno --sunny, jak i --cloudy może spowodować wyświetlenie stylu częściowo pochmurnego.

Aktualizowanie wartości właściwości niestandardowych za pomocą JavaScript może odbywać się bezproblemowo, zarówno podczas konfigurowania modelu DOM (czyli podczas tworzenia komponentu w frameworku), jak i w dowolnym momencie za pomocą <parentElem>.style.setProperty('--myProperty’, <value>). I

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

Stylizowanie karty za pomocą zapytań o styl. JavaScript używany 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. Możesz spodziewać się więcej funkcji zapytań o kontener, które pomogą Ci tworzyć dynamiczne, elastyczne interfejsy. Jeśli chodzi o zapytania o styl, nadal jest kilka otwartych problemów. Jednym z nich jest implementacja zapytań o styl w przypadku stylów CSS innych niż właściwości niestandardowe. Jest to już część obecnego poziomu specyfikacji, ale nie jest jeszcze zaimplementowane w żadnej przeglądarce. Oczekuje się, że ocena kontekstu logicznego zostanie dodana do obecnego poziomu specyfikacji po rozwiązaniu nierozwiązanego problemu, a wysyłanie zapytań o zakres jest planowane na następny poziom specyfikacji.