Aan de slag met stijlquery's

De mogelijkheid om de inline-grootte van een ouderelement en de query-eenheidswaarden van een container op te vragen, wordt sinds kort stabiel ondersteund door alle moderne browserengines .

Browser Support

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

Source

De containment-specificatie omvat echter meer dan alleen query's op basis van grootte; het maakt het ook mogelijk om de stijlwaarden van een ouderelement op te vragen. Vanaf Chromium 111 kunt u stijlcontainment toepassen op aangepaste eigenschapswaarden en een ouderelement opvragen voor de waarde van een aangepaste eigenschap.

Browser Support

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

Dit betekent dat we nog meer logische controle hebben over stijlen in CSS, en dat de logica en datalaag van een applicatie beter gescheiden kunnen worden van de stijlen.

De CSS Containment Module Level 3-specificatie, die betrekking heeft op size- en stylequeries, maakt het mogelijk om alle stijlen van een parent-element op te vragen, inclusief eigenschap-waardeparen zoals font-weight: 800 . In de huidige fase van de uitrol werken stylequeries echter alleen met aangepaste CSS-eigenschapswaarden. Dit is nog steeds erg handig voor het combineren van stijlen en het scheiden van data en design. Laten we eens kijken hoe je stylequeries 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>

Om stijlquery's te gebruiken, moet je eerst een containerelement instellen. Dit vereist een iets andere aanpak, afhankelijk van of je een query uitvoert op een direct of indirect ouderelement.

Het opvragen van gegevens bij directe ouders

Diagram van een stijlquery.

Anders dan bij stijlqueries, hoef je geen containment toe te passen met behulp van de container-type of container eigenschap op .card-container om .card de stijlen van zijn directe ouder te laten opvragen. We moeten de stijlen (in dit geval aangepaste eigenschapswaarden) echter wel toepassen op een container (in dit geval .card-container ) of een element dat het element bevat dat we stylen in de DOM. We kunnen de stijlen die we opvragen niet rechtstreeks toepassen op het element dat we stylen met die query, omdat dit oneindige lussen zou kunnen veroorzaken.

Om een ​​ouder direct op te vragen, kunt u het volgende schrijven:

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

Je hebt misschien gemerkt dat de stijlquery de query omwikkelt met style() . Dit is om onderscheid te maken tussen groottewaarden en stijlen. Je kunt bijvoorbeeld een query schrijven voor de breedte van de container als @container (min-width: 200px) { … } . Dit zou stijlen toepassen als de oudercontainer minstens 200px breed is. min-width kan echter ook een CSS-eigenschap zijn, en je zou de CSS-waarde van min-width kunnen opvragen met behulp van stijlqueries. Daarom gebruik je de ` style() -wrapper om het verschil duidelijk te maken: @container style(min-width: 200px) { … } .

Styling van niet-directe ouders

Als je stijlen wilt opvragen voor een 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 goede gewoonte om je containers namen te geven, zodat duidelijk is wat je opvraagt ​​en je de containers gemakkelijker kunt benaderen. Een voorbeeld hiervan is wanneer je elementen binnen .card rechtstreeks wilt stylen. Zonder een benoemde container voor .card-container is het niet mogelijk om deze rechtstreeks op te vragen.

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

Stijlquery's in actie

Demo-afbeelding met meerdere productkaarten, waarvan sommige de labels 'nieuw' of 'beperkte voorraad' hebben en de kaart met 'beperkte voorraad' een rode achtergrond heeft.

Stijlquery's zijn met name handig wanneer je een herbruikbaar component met meerdere varianten hebt, of wanneer je niet alle stijlen onder controle hebt, maar in bepaalde gevallen wel wijzigingen wilt aanbrengen. Dit voorbeeld toont een set productkaarten die hetzelfde kaartcomponent delen. Sommige productkaarten hebben extra details/notities zoals 'Nieuw' of 'Beperkte voorraad', die worden geactiveerd door een aangepaste eigenschap met de naam --detail . Bovendien krijgt een product met een beperkte voorraad een donkerrode rand. Dit soort informatie wordt waarschijnlijk aan de serverzijde gerenderd en kan via inline stijlen op de kaarten worden toegepast, zoals hieronder weergegeven:

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

Met deze gestructureerde data kun je waarden doorgeven aan --detail en deze 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;
  }
}

De bovenstaande code stelt ons in staat om een ​​chip toe te passen voor --detail: low-stock en --detail: new , maar u hebt wellicht wat redundantie in het codeblok opgemerkt. Momenteel is er geen manier om alleen de aanwezigheid van --detail op te vragen met @container style(--detail) , wat een betere uitwisseling van stijlen en minder herhaling mogelijk zou maken. Deze functionaliteit 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 je kunt het ook anders aanpakken door meerdere aangepaste eigenschappen te gebruiken en op te vragen. Neem bijvoorbeeld dit voorbeeld van een weerkaart:

Demonstratie van weerkaarten.

Om de achtergrondkleuren en pictogrammen voor deze kaarten vorm te geven, zoek je 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 kunt u elke kaart vormgeven op basis van zijn unieke kenmerken. Maar u kunt ook vormgeven op basis van combinaties van kenmerken (aangepaste eigenschappen), met behulp van de combinator and op dezelfde manier als bij mediaqueries . Een dag die zowel bewolkt als zonnig is, zou er bijvoorbeeld zo uitzien:

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

Het scheiden van data en ontwerp.

In beide demo's is er een structureel voordeel verbonden aan het scheiden van de datalaag (de DOM die op de pagina wordt weergegeven) van de toegepaste stijlen. De stijlen worden geschreven als mogelijke varianten die binnen de stijl van de component bestaan, terwijl een endpoint de data kan verzenden die vervolgens wordt gebruikt om de component te stylen. Je kunt een enkele waarde gebruiken, zoals in het eerste geval, het bijwerken van de --detail waarde, of meerdere variabelen, zoals in het tweede geval (het instellen van --rainy , --cloudy of --sunny . En het beste is dat je deze waarden ook kunt combineren; controleren op zowel --sunny als --cloudy kan bijvoorbeeld een stijl voor gedeeltelijk bewolkte lucht weergeven.

Het bijwerken van aangepaste eigenschapswaarden via JavaScript kan naadloos gebeuren, zowel tijdens het instellen van het DOM-model (bijvoorbeeld tijdens het bouwen van de component in een framework) als op elk gewenst moment met behulp van <parentElem>.style.setProperty('--myProperty', <value>) .

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

Geef de kaart stijl met behulp van stijlquery's. De JavaScript-code die wordt gebruikt om de waarden van de aangepaste eigenschappen 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 slechts het begin. U kunt meer verwachten van containerqueries die u helpen bij het bouwen van dynamische, responsieve interfaces. Wat stijlqueries betreft, zijn er nog een paar openstaande kwesties. Een daarvan is de implementatie van stijlqueries voor CSS-stijlen die verder gaan dan aangepaste eigenschappen. Dit is al onderdeel van het huidige specificatieniveau, maar nog niet geïmplementeerd in browsers. De evaluatie van de booleaanse context zal naar verwachting aan het huidige specificatieniveau worden toegevoegd zodra de openstaande kwestie is opgelost, terwijl bereikqueries gepland staan ​​voor het volgende specificatieniveau.