Aan de slag met stijlquery's

De mogelijkheid om de inlinegrootte van een ouder en de waarden van containerquery-eenheden op te vragen, heeft onlangs stabiele ondersteuning gekregen in alle moderne browserengines .

Browserondersteuning

  • Chroom: 105.
  • Rand: 105.
  • Firefox: 110.
  • Safari: 16.

Bron

De containmentspecificatie omvat echter meer dan alleen vragen over de grootte; het maakt het ook mogelijk om de stijlwaarden van een ouder op te vragen. Vanaf Chromium 111 kun je stijlinsluiting toepassen op aangepaste eigenschapswaarden en een bovenliggend element opvragen voor de waarde van een aangepaste eigenschap.

Browserondersteuning

  • Chroom: 111.
  • Rand: 111.
  • Firefox: niet ondersteund.
  • Safari: 18.

Bron

Dit betekent dat we nog meer logische controle hebben over stijlen in CSS, en een betere scheiding mogelijk maken tussen de logica en gegevenslaag van een applicatie en de stijlen ervan.

De CSS Containment Module Level 3-specificatie, die zoekopdrachten naar grootte en stijl omvat, maakt het mogelijk om alle stijlen op te vragen bij een ouder, inclusief eigenschap- en waardeparen zoals font-weight: 800 . Bij de uitrol van deze functie werken stijlquery's momenteel echter alleen met aangepaste CSS-eigenschapswaarden. Dit is nog steeds erg handig voor het combineren van stijlen en het scheiden van gegevens en ontwerp. Laten we eens kijken hoe u stijlquery's gebruikt met aangepaste CSS-eigenschappen:

Aan de slag met stijlquery's

Stel dat we de volgende HTML hebben:

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

Als u stijlquery's wilt gebruiken, moet u eerst een containerelement instellen. Dit vereist een enigszins andere aanpak, afhankelijk van of u een directe of indirecte ouder ondervraagt.

Directe ouders bevragen

Diagram van een stijlquery.

In tegenstelling tot stijlquery's hoeft u geen containment toe te passen met behulp van de container-type of container eigenschap op .card-container zodat .card de stijlen van zijn directe ouder kan opvragen. We moeten de stijlen (in dit geval aangepaste eigenschapswaarden) echter wel toepassen op een container (in dit geval .card-container ) of op elk element dat het element bevat dat we in de DOM stylen. We kunnen de stijlen waarop we een query uitvoeren, niet toepassen op het directe element dat we met die query stylen, omdat dit oneindige lussen kan veroorzaken.

Om rechtstreeks een ouder te ondervragen, kunt u schrijven:

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

Het is je misschien opgevallen dat de stijlquery de query omhult met style() . Dit is om maatwaarden te onderscheiden van stijlen. U kunt bijvoorbeeld een query voor de breedte van de container schrijven als @container (min-width: 200px) { … } . Hiermee worden stijlen toegepast als de bovenliggende container minimaal 200 px breed is. min-width kan echter ook een CSS-eigenschap zijn, en u kunt de CSS-waarde van min-width opvragen met behulp van stijlquery's. Daarom zou je de wrapper style() gebruiken om het verschil duidelijk te maken: @container style(min-width: 200px) { … } .

Styling van niet-directe ouders

Als je stijlen wilt opvragen voor elk element dat geen direct bovenliggend element is, moet je dat element een container-name geven. We kunnen bijvoorbeeld stijlen toepassen op .card op basis van de stijlen van .card-list door .card-list een container-name te geven en ernaar te verwijzen in de stijlquery.

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

Het is over het algemeen een best practice om uw containers namen te geven om duidelijk te maken wat u vraagt ​​en om de mogelijkheid te ontgrendelen om gemakkelijker toegang te krijgen tot die containers. Een voorbeeld waarbij dit van pas komt is als je elementen binnen .card rechtstreeks wilt opmaken. Zonder een benoemde container op .card-container kunnen ze deze niet rechtstreeks opvragen.

Maar dit alles is in de praktijk veel logischer. Laten we een paar voorbeelden bekijken:

Stijlquery's in actie

Demoafbeelding met meerdere productkaarten, sommige met ‘nieuw’ of ‘low stock’ tags en de ‘low stock’ kaart met een rode achtergrond.

Stijlquery's zijn vooral handig als u een herbruikbare component met meerdere varianten heeft, of als u niet over al uw stijlen beschikt, maar in bepaalde gevallen wijzigingen moet aanbrengen. Dit voorbeeld toont een set productkaarten die hetzelfde kaartonderdeel delen. Sommige productkaarten hebben aanvullende details/opmerkingen, zoals 'Nieuw' of 'Lage voorraad', geactiveerd door een aangepaste eigenschap met de naam --detail . Als een product zich in de categorie 'Lage voorraad' bevindt, krijgt het bovendien een dieprode randachtergrond. Dit soort informatie wordt waarschijnlijk door de server weergegeven en kan op de kaarten worden toegepast via inline-stijlen, zoals:

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

Gegeven deze gestructureerde gegevens kunt u waarden doorgeven aan --detail en deze aangepaste CSS-eigenschap gebruiken om de stijlen toe te passen:

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

Met de bovenstaande code kunnen we een chip toepassen voor --detail: low-stock en --detail: new , maar het kan zijn dat je enige redundantie in het codeblok hebt opgemerkt. Momenteel is er geen manier om alleen naar de aanwezigheid van --detail te vragen met @container style(--detail) , wat een beter delen van stijlen en minder herhaling mogelijk zou maken. Deze mogelijkheid wordt momenteel besproken in de werkgroep.

Weerkaarten

In het vorige voorbeeld werd één aangepaste eigenschap met meerdere mogelijke waarden gebruikt om stijlen toe te passen. Maar u kunt het ook door elkaar halen door meerdere aangepaste eigenschappen te gebruiken en er query's op uit te voeren. Neem dit voorbeeld van een weerkaart:

Demo voor weerkaarten.

Om de achtergrondverlopen en pictogrammen voor deze kaarten vorm te geven, zoekt u naar weerskenmerken, zoals ‘bewolkt’, ‘regenachtig’ of ‘zonnig’:

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

Op deze manier kun je elke kaart stylen op basis van zijn unieke kenmerken. Maar u kunt ook karakteristieke (aangepaste eigenschap)combinaties stylen, waarbij u de combinator and op dezelfde manier gebruikt als voor mediaquery's . Een dag die zowel bewolkt als zonnig is, ziet er bijvoorbeeld als volgt uit:

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

Gegevens scheiden van ontwerp

In beide demo's is er een structureel voordeel van het scheiden van de gegevenslaag (DOM die op de pagina zou worden weergegeven) van de toegepaste stijlen. De stijlen zijn geschreven als mogelijke varianten die binnen de componentenstijl leven, terwijl een eindpunt de gegevens zou kunnen verzenden die het vervolgens zou gebruiken om de component op te maken. U kunt een enkele waarde gebruiken, zoals in het eerste geval, waarbij u de waarde --detail bijwerkt, of meerdere variabelen, zoals in het tweede geval (instelling --rainy of --cloudy of --sunny . En het beste is is dat je deze waarden ook kunt combineren, waarbij het controleren van zowel --sunny als --cloudy een gedeeltelijk bewolkte stijl kan opleveren.

Het bijwerken van aangepaste eigenschapswaarden via JavaScript kan naadloos worden gedaan, hetzij tijdens het instellen van het DOM-model (dat wil zeggen tijdens het bouwen van de component in een raamwerk), of op elk gewenst moment worden bijgewerkt met <parentElem>.style.setProperty('--myProperty', <value>) . I

Hier is een demo die in een paar regels code het --theme van een knop bijwerkt, en stijlen toepast met behulp van stijlquery's en die aangepaste eigenschap ( --theme ):

Stijl de kaart met behulp van stijlquery's. Het JavaScript dat wordt gebruikt om de aangepaste eigenschapswaarden bij te werken is:

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

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

De functies die in dit artikel worden beschreven, zijn nog maar het begin. U kunt meer verwachten van containerquery's om u te helpen dynamische, responsieve interfaces te bouwen. Wat specifiek de stijlquery's betreft, zijn er nog enkele openstaande kwesties. Eén daarvan is de implementatie van stijlquery's voor CSS-stijlen die verder gaan dan aangepaste eigenschappen. Dit maakt al deel uit van het huidige specificatieniveau, maar is nog in geen enkele browser geïmplementeerd. De Booleaanse contextevaluatie zal naar verwachting worden toegevoegd aan het huidige specificatieniveau wanneer het openstaande probleem is opgelost, terwijl bereikquery's zijn gepland voor het volgende niveau van de specificatie.