Come utilizzare subito le query sui container

Di recente, Chris Coyier ha scritto un post del blog in cui poneva la seguente domanda:

Ora che le query dei container sono supportate in tutti i motori dei browser, perché non sono più utilizzate dagli sviluppatori?

Il post di Chris elenca una serie di potenziali motivi (ad esempio, mancanza di consapevolezza, vecchie abitudini muoiono difficili), ma c'è un motivo particolare che è evidente.

Alcuni sviluppatori affermano di voler utilizzare subito le query dei container, ma non è possibile perché devono ancora supportare i browser meno recenti.

Come avrai intuito dal titolo, riteniamo che attualmente la maggior parte degli sviluppatori possa utilizzare le query container, in produzione, anche se devi supportare i browser meno recenti. Questo post illustra l'approccio che consigliamo di adottare.

Un approccio pragmatico

Se vuoi utilizzare ora le query container nel codice, ma vuoi che l'esperienza sia uguale in tutti i browser, puoi implementare un fallback basato su JavaScript per i browser che non supportano le query container.

La domanda diventa quindi: quanto dovrebbe essere completo il fallback?

Come per tutti i video di riserva, la sfida consiste nel trovare un buon equilibrio tra utilità e prestazioni. Per le funzionalità CSS, spesso è impossibile supportare l'API completa (vedi perché non utilizzare un polyfill). Tuttavia, è possibile andare abbastanza lontano identificando l'insieme di funzionalità di base che la maggior parte degli sviluppatori vuole utilizzare, per poi ottimizzare i contenuti di riserva solo per quelle funzionalità.

Ma qual è l'"insieme di funzionalità di base" richiesto dalla maggior parte degli sviluppatori per le query sui container? Per rispondere a questa domanda, valuta in che modo la maggior parte degli sviluppatori crea siti adattabili attualmente con query supporti.

Quasi tutti i moderni sistemi di progettazione e librerie dei componenti sono stati standardizzati sulla base di principi di mobile-first, implementati utilizzando un insieme di punti di interruzione predefiniti (ad esempio SM, MD, LG e XL). Per impostazione predefinita, i componenti sono ottimizzati per essere visualizzati bene sugli schermi di piccole dimensioni, quindi gli stili vengono sovrapposti in modo condizionale per supportare un insieme fisso di larghezze dello schermo più grandi. (per alcuni esempi, consulta la documentazione di Bootstrap e Tailwind.)

Questo approccio è rilevante tanto per i sistemi di progettazione basati su container quanto per i sistemi di progettazione basati su aree visibili, perché nella maggior parte dei casi ciò che conta per i designer non è la dimensione dello schermo o dell'area visibile, ma la quantità di spazio disponibile per il componente nel contesto in cui è stato posizionato. In altre parole, piuttosto che i punti di interruzione relativi all'intera area visibile (e applicabili all'intera pagina), i punti di interruzione vengono applicati ad aree di contenuti specifiche, come le barre laterali, le finestre di dialogo modali o i corpi dei post.

Se sei in grado di lavorare rispettando i vincoli di un approccio basato sui punti di interruzione mobile-first (al momento fa la maggior parte degli sviluppatori), l'implementazione di un fallback basato su container per questo approccio è molto più semplice rispetto all'implementazione del supporto completo per ogni singola funzionalità di query sui container.

Nella sezione successiva viene illustrato esattamente come funziona tutto questo, oltre a una guida passo passo che mostra come implementarlo su un sito esistente.

Come funziona

Passaggio 1. Aggiorna gli stili dei componenti per utilizzare le regole @container anziché @media

In questo primo passaggio, identifica tutti i componenti del tuo sito che ritieni possano trarre vantaggio dal dimensionamento basato sui contenitori anziché in quello dell'area visibile.

È una buona idea iniziare con uno o due componenti per vedere come funziona questa strategia, ma se vuoi convertire il 100% dei componenti in stili basati su container, va bene lo stesso. L'aspetto migliore di questa strategia è che, se necessario, può essere adottata in modo incrementale.

Una volta identificati i componenti da aggiornare, dovrai modificare ogni regola @media nel CSS di quei componenti in una regola @container. Puoi mantenere invariate le condizioni relative alle dimensioni.

Se il CSS utilizza già un insieme di punti di interruzione predefiniti, puoi continuare a utilizzarli esattamente come sono definiti. Se non utilizzi già punti di interruzione predefiniti, devi definirne i nomi (di cui ti riferirai in seguito in JavaScript; consulta il passaggio 2 in merito).

Di seguito è riportato un esempio di stili per un componente .photo-gallery che, per impostazione predefinita, è una singola colonna, quindi aggiorna lo stile in due e tre colonne nei punti di interruzione MD e XL (rispettivamente):

.photo-gallery {
  display: grid;
  grid-template-columns: 1fr;
}

/* Styles for the `MD` breakpoint */
@media (min-width: 768px) {
  .photo-gallery {
    grid-template-columns: 1fr 1fr;
  }
}

/* Styles for the `XL` breakpoint */
@media (min-width: 1280px) {
  .photo-gallery {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

Per cambiare gli stili dei componenti dall'utilizzo delle regole @media all'utilizzo delle regole @container, esegui una ricerca e sostituisci nel codice:

/* Before: */
@media (min-width: 768px) { /* ... */ }
@media (min-width: 1280px) { /* ... */ }

/* After: */
@container (min-width: 768px) { /* ... */ }
@container (min-width: 1280px) { /* ... */ }

Dopo aver aggiornato gli stili dei componenti da @media regole a regole @container basate su punti di interruzione, il passaggio successivo consiste nel configurare gli elementi contenitore.

Passaggio 2. Aggiungi elementi del contenitore al codice HTML

Il passaggio precedente ha definito gli stili dei componenti basati sulle dimensioni di un elemento contenitore. Il passaggio successivo consiste nel definire quali elementi della pagina devono essere elementi contenitore le cui dimensioni saranno relative alle regole @container.

Puoi dichiarare qualsiasi elemento come elemento contenitore in CSS impostando la relativa proprietà container-type su size o inline-size. Se le regole del container si basano sulla larghezza, generalmente ti conviene utilizzare inline-size.

Prendi in considerazione un sito con la seguente struttura HTML di base:

<body>
  <div class="sidebar">...</div>
  <div class="content">...</div>
</body>

Per rendere containers gli elementi .sidebar e .content di questo sito, aggiungi questa regola al tuo CSS:

.content, .sidebar {
  container-type: inline-size;
}

Per i browser che supportano le query contenitore, questo CSS è tutto quello di cui hai bisogno per creare gli stili dei componenti definiti nel passaggio precedente in relazione all'area dei contenuti principale o alla barra laterale, a seconda dell'elemento in cui si trovano.

Tuttavia, per i browser che non supportano le query sui container, è necessario eseguire alcune operazioni aggiuntive.

Devi aggiungere un codice che rilevi quando le dimensioni degli elementi container cambiano e quindi aggiorna il DOM in base a queste modifiche in modo che il tuo CSS possa collegarsi.

Per fortuna, il codice necessario è minimo e può essere completamente astratto in un componente condiviso da utilizzare su qualsiasi sito e in qualsiasi area di contenuti.

Il seguente codice definisce un elemento <responsive-container> riutilizzabile che ascolta automaticamente le modifiche delle dimensioni e aggiunge classi di punti di interruzione su cui il CSS può applicare uno stile:

// A mapping of default breakpoint class names and min-width sizes.
// Redefine these as needed based on your site's design.
const defaultBreakpoints = {SM: 512, MD: 768, LG: 1024, XL: 1280};

// A resize observer that monitors size changes to all <responsive-container>
// elements and calls their `updateBreakpoints()` method with the updated size.
const ro = new ResizeObserver((entries) => {
  entries.forEach((e) => e.target.updateBreakpoints(e.contentRect));
});

class ResponsiveContainer extends HTMLElement {
  connectedCallback() {
    const bps = this.getAttribute('breakpoints');
    this.breakpoints = bps ? JSON.parse(bps) : defaultBreakpoints;
    this.name = this.getAttribute('name') || '';
    ro.observe(this);
  }
  disconnectedCallback() {
    ro.unobserve(this);
  }
  updateBreakpoints(contentRect) {
    for (const bp of Object.keys(this.breakpoints)) {
      const minWidth = this.breakpoints[bp];
      const className = this.name ? `${this.name}-${bp}` : bp;
      this.classList.toggle(className, contentRect.width >= minWidth);
    }
  }
}

self.customElements.define('responsive-container', ResponsiveContainer);

Questo codice funziona creando un strumento ResizeObserver che ascolti automaticamente le modifiche alle dimensioni di qualsiasi elemento <responsive-container> nel DOM. Se la modifica delle dimensioni corrisponde a una delle dimensioni dei punti di interruzione definite, viene aggiunta all'elemento una classe con quel nome di punto di interruzione, che viene rimossa se la condizione non corrisponde più.

Ad esempio, se il valore width dell'elemento <responsive-container> è compreso tra 768 e 1024 pixel (in base ai valori predefiniti dei punti di interruzione impostati nel codice), verranno aggiunte le classi SM e MD, in questo modo:

<responsive-container class="SM MD">...</responsive-container>

Queste classi ti consentono di definire gli stili di riserva per i browser che non supportano le query contenitore (consulta il passaggio 3: aggiungi stili di riserva al tuo CSS).

Per aggiornare il codice HTML precedente per utilizzare questo elemento contenitore, modifica gli elementi <div> della barra laterale e del contenuto principale in modo che siano elementi <responsive-container>:

<body>
  <responsive-container class="sidebar">...</responsive-container>
  <responsive-container class="content">...</responsive-container>
</body>

Nella maggior parte dei casi, puoi semplicemente utilizzare l'elemento <responsive-container> senza alcuna personalizzazione, ma se hai bisogno di personalizzarlo, sono disponibili le seguenti opzioni:

  • Dimensioni personalizzate dei punti di interruzione: questo codice utilizza un insieme di nomi di classi di punti di interruzione e dimensioni min-width predefinite, ma vengono modificati nel modo che preferisci. Puoi anche sostituire questi valori a livello di singolo elemento utilizzando l'attributo breakpoints.
  • Container denominati: questo codice supporta anche i container denominati passando un attributo name. Questo può essere importante se devi nidificare gli elementi del contenitore. Consulta la sezione Limitazioni per ulteriori dettagli.

Ecco un esempio che imposta entrambe le opzioni di configurazione:

<responsive-container
  name='sidebar'
  breakpoints='{"bp1":500,"bp2":1000,"bp3":1500}'>
</responsive-container>

Infine, quando raggruppi questo codice, assicurati di utilizzare il rilevamento delle funzionalità e il formato import() dinamico per caricarlo solo se il browser non supporta le query sul container.

if (!CSS.supports('container-type: inline-size')) {
  import('./path/to/responsive-container.js');
}

Passaggio 3. Aggiungi stili di riserva al CSS

L'ultimo passaggio in questa strategia consiste nell'aggiungere stili di riserva per i browser che non riconoscono quelli definiti nelle regole @container. Per farlo, duplica queste regole utilizzando le classi di punti di interruzione impostate sugli elementi <responsive-container>.

Continuando con l'esempio .photo-gallery di prima, gli stili di riserva per le due regole @container potrebbero avere il seguente aspetto:

/* Container query styles for the `MD` breakpoint. */
@container (min-width: 768px) {
  .photo-gallery {
    grid-template-columns: 1fr 1fr;
  }
}

/* Fallback styles for the `MD` breakpoint. */
@supports not (container-type: inline-size) {
  :where(responsive-container.MD) .photo-gallery {
    grid-template-columns: 1fr 1fr;
  }
}

/* Container query styles for the `XL` breakpoint. */
@container (min-width: 1280px) {
  .photo-gallery {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

/* Fallback styles for the `XL` breakpoint. */
@supports not (container-type: inline-size) {
  :where(responsive-container.XL) .photo-gallery {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

In questo codice, per ogni regola @container esiste una regola equivalente che corrisponde in modo condizionale all'elemento <responsive-container> se è presente la classe di punti di interruzione corrispondente.

La porzione del selettore corrispondente all'elemento <responsive-container> è racchiusa in un selettore funzionale pseudo-classe :where(), per mantenere la specificità del selettore di riserva equivalente a quella del selettore originale all'interno della regola @container.

Ogni regola di riserva è inclusa anche in una dichiarazione @supports. Sebbene ciò non sia strettamente necessario affinché il fallback funzioni, significa che il browser ignora completamente queste regole se supporta le query sui container, il che può migliorare le prestazioni della corrispondenza degli stili in generale. Potenzialmente, consente inoltre agli strumenti di creazione o alle CDN di rimuovere queste dichiarazioni se sanno che il browser supporta le query sui container e non ha bisogno di quegli stili di fallback.

Lo svantaggio principale di questa strategia di riserva è che richiede di ripetere due volte la dichiarazione dello stile, il che è noioso e soggetto a errori. Tuttavia, se utilizzi un preprocessore CSS, puoi astrarre questo controllo in un mix che genera sia la regola @container sia il codice di fallback per te. Ecco un esempio di utilizzo di Sass:

@use 'sass:map';

$breakpoints: (
  'SM': 512px,
  'MD': 576px,
  'LG': 1024px,
  'XL': 1280px,
);

@mixin breakpoint($breakpoint) {
  @container (min-width: #{map.get($breakpoints, $breakpoint)}) {
    @content();
  }
  @supports not (container-type: inline-size) {
    :where(responsive-container.#{$breakpoint}) & {
      @content();
    }
  }
}

Una volta ottenuto questo mix, puoi aggiornare gli stili del componente .photo-gallery originali in modo da eliminare completamente la duplicazione:

.photo-gallery {
  display: grid;
  grid-template-columns: 1fr;

  @include breakpoint('MD') {
    grid-template-columns: 1fr 1fr;
  }

  @include breakpoint('XL') {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

E questo è tutto!

Riepilogo

Ricapitolando, ecco come aggiornare il codice per utilizzare subito le query container con un fallback cross-browser.

  1. Componenti dell'identità a cui vuoi applicare uno stile in base al contenitore e aggiorna le regole @media nel CSS per utilizzare le regole @container. Inoltre, se non l'hai già fatto, standardizza in base a un set di nomi di punti di interruzione in modo che corrispondano alle condizioni di dimensione nelle regole del container.
  2. Aggiungi il codice JavaScript alla base dell'elemento <responsive-container> personalizzato, quindi aggiungi l'elemento <responsive-container> a tutte le aree di contenuti della pagina a cui vuoi associare i componenti.
  3. Per supportare browser meno recenti, aggiungi al CSS stili di riserva che corrispondano alle classi di punti di interruzione che vengono aggiunte automaticamente agli elementi <responsive-container> nel codice HTML. Idealmente, usa un mixin del preprocessore CSS per evitare di dover scrivere due volte gli stessi stili.

L'aspetto migliore di questa strategia è che prevede un costo di configurazione una tantum, ma successivamente non sono necessari ulteriori sforzi per aggiungere nuovi componenti e definire gli stili relativi al container.

Come funziona

Probabilmente il modo migliore per capire come si combinano tutti questi passaggi è quello di guardarne una demo in azione.

Un video di un utente che interagisce con il sito demo di query contenitore. L'utente sta ridimensionando le aree dei contenuti per mostrare come si aggiornano gli stili dei componenti in base alle dimensioni dell'area.

Questa demo è una versione aggiornata di un sito creato nel 2019 (prima che esistessero le query contenitore) per illustrare perché le query container sono essenziali per creare librerie dei componenti realmente reattive.

Dal momento che questo sito aveva già definito stili per una serie di "componenti adattabili", si è rivelato un candidato perfetto per testare la strategia introdotta qui su un sito non banale. A quanto pare, l'aggiornamento è stato piuttosto semplice e non richiedeva praticamente nessuna modifica agli stili originali del sito.

Puoi consultare il codice sorgente della demo completo su GitHub e controllare nello specifico il codice sorgente del componente demo per vedere come vengono definiti gli stili di fallback. Se vuoi testare solo il comportamento di riserva, è disponibile una demo solo di riserva che include solo questa variante, anche nei browser che supportano le query dei container.

Limitazioni e potenziali miglioramenti

Come menzionato all'inizio di questo post, la strategia qui descritta funziona bene nella maggior parte dei casi d'uso che gli sviluppatori interessano effettivamente quando raggiungono le query dei container.

Detto questo, esistono alcuni casi d'uso più avanzati che questa strategia non tenta intenzionalmente di supportare. Questi sono i seguenti argomenti:

Unità di query container

La specifica per le query contenitore definisce una serie di nuove unità, tutte relative alle dimensioni del contenitore. Sebbene potenzialmente utile in alcuni casi, è probabile che la maggior parte dei design adattabili possa essere realizzata con mezzi esistenti, come le percentuali o l'utilizzo di layout a griglia o flessibili.

Detto questo, se devi utilizzare le unità di query container, puoi aggiungerne facilmente il supporto utilizzando le proprietà personalizzate. In particolare, definendo una proprietà personalizzata per ogni unità utilizzata nell'elemento contenitore, in questo modo:

responsive-container {
  --cqw: 1cqw;
  --cqh: 1cqh;
}

Ogni volta che devi accedere alle unità di query del container, utilizza queste proprietà anziché l'unità stessa:

.photo-gallery {
  font-size: calc(10 * var(--cqw));
}

Poi, per supportare i browser meno recenti, imposta i valori per le proprietà personalizzate nell'elemento contenitore all'interno del callback ResizeObserver.

class ResponsiveContainer extends HTMLElement {
  // ...
  updateBreakpoints(contentRect) {
    this.style.setProperty('--cqw', `${contentRect.width / 100}px`);
    this.style.setProperty('--cqh', `${contentRect.height / 100}px`);

    // ...
  }
}

In questo modo, hai la possibilità di "passare" questi valori da JavaScript a CSS e di avere tutta la potenza del CSS (ad esempio, calc(), min(), max(), clamp()) per manipolarli secondo le necessità.

Supporto delle proprietà logiche e della modalità di scrittura

Potresti aver notato l'utilizzo di inline-size anziché di width nelle dichiarazioni @container in alcuni di questi esempi di CSS. Potresti aver notato anche le nuove unità cqi e cqb (rispettivamente per le dimensioni in linea e in blocco). Queste nuove funzionalità riflettono lo spostamento del CSS verso proprietà e valori logici anziché fisici o direzionali.

Purtroppo, API come Ridimensiona Observer registrano comunque i valori in width e height, quindi se i tuoi progetti hanno bisogno della flessibilità delle proprietà logiche, devi scoprirlo autonomamente.

Sebbene sia possibile ottenere la modalità di scrittura utilizzando un passaggio come getComputedStyle() nell'elemento container, questa operazione ha un costo e non esiste un modo valido per rilevare se la modalità di scrittura cambia.

Per questo motivo, l'approccio migliore è che l'elemento <responsive-container> stesso accetti una proprietà in modalità di scrittura che il proprietario del sito può impostare (e aggiornare) in base alle necessità. Per implementarlo, devi seguire lo stesso approccio mostrato nella sezione precedente e scambiare width e height in base alle esigenze.

Contenitori nidificati

La proprietà container-name ti consente di assegnare un nome a un contenitore, che potrai poi fare riferimento in una regola @container. I container denominati sono utili se hai container nidificati all'interno di container e hai bisogno che determinate regole corrispondano solo a determinati container (non solo al container predecessore più vicino).

La strategia di riserva qui descritta utilizza il combinatore discendente per applicare uno stile agli elementi che corrispondono a determinate classi di punti di interruzione. Questo può non funzionare se hai container nidificati, poiché un numero qualsiasi di classi di punti di interruzione di più predecessori di elementi container potrebbe corrispondere contemporaneamente a un determinato componente.

Ad esempio, qui sono presenti due elementi <responsive-container> che racchiudono il componente .photo-gallery, ma poiché il container esterno è più grande di quello interno, sono state aggiunte classi di punti di interruzione diverse.

<responsive-container class="SM MD LG">
  ...
  <responsive-container class="SM">
    ...
    <div class="photo-gallery">...</div class="photo-gallery">
  </responsive-container>
</responsive-container>

In questo esempio, le classi MD e LG nel container esterno influirebbero sulle regole di stile corrispondenti al componente .photo-gallery, che non corrisponde al comportamento delle query sul container (dato che corrispondono solo al container predecessore più vicino).

Per risolvere il problema:

  1. Assicurati di assegnare sempre un nome ai container che stai nidificando, quindi assicurati che le classi dei punti di interruzione abbiano come prefisso il nome del container per evitare conflitti.
  2. Usa il combinatore figlio invece del combinatore discendente nei selettori di fallback (che è un po' più limitante).

Nella sezione Contenitori nidificati del sito demo è riportato un esempio di questo funzionamento in cui vengono utilizzati contenitori denominati, oltre al mixin Sass che utilizza nel codice per generare gli stili di riserva per le regole @container denominate e senza nome.

E per quanto riguarda i browser che non supportano :where(), Elementi personalizzati o Ridimensiona Observer?

Anche se queste API possono sembrare relativamente nuove, sono tutte supportate in tutti i browser da più di tre anni e fanno tutte parte di Baseline ampiamente disponibile.

Pertanto, a meno che tu non disponga di dati che indicano che una parte significativa dei visitatori del tuo sito utilizza browser che non supportano una di queste funzionalità, non c'è motivo di non usarli liberamente senza una funzionalità di riserva.

Anche in questo caso, per questo caso d'uso specifico, la cosa peggiore che possa capitare è che la creatività di riserva non funziona per una percentuale molto ridotta di utenti, il che significa che vedranno la visualizzazione predefinita anziché una visualizzazione ottimizzata in base alle dimensioni del contenitore.

La funzionalità del sito dovrebbe continuare a funzionare ed è questo che conta davvero.

Perché non usare semplicemente un polyfill di query container?

Le funzionalità CSS sono notoriamente difficili da compilare e in genere richiedono la reimplementazione dell'intero parser CSS e della logica cascade del browser in JavaScript. Di conseguenza, gli autori di polyfill CSS devono fare molti compromessi che quasi sempre presentano numerose limitazioni alle funzionalità e un significativo sovraccarico delle prestazioni.

Per questi motivi, in genere sconsigliamo di utilizzare i polyfill CSS in produzione, incluso container-query-polyfill di Google Chrome Labs, che non è più gestito (e destinato principalmente a scopi dimostrativi).

La strategia di riserva discussa qui presenta meno limitazioni, richiede molto meno codice e avrà un rendimento notevolmente migliore rispetto a qualsiasi altro polyfill delle query dei container.

Hai bisogno di implementare una soluzione di riserva per i browser meno recenti?

Se sei preoccupato per una delle limitazioni menzionate qui, probabilmente vale la pena chiederti se hai effettivamente bisogno di implementare una soluzione di riserva. Dopotutto, il modo più semplice per evitare queste limitazioni è utilizzare la funzionalità senza alcun tipo di riserva. In molti casi, onestamente, potrebbe essere una scelta perfettamente ragionevole.

Secondo caniuse.com, le query sui container sono supportate dal 90% degli utenti di internet a livello mondiale e, per molte persone che leggono questo post, questo numero è probabilmente molto più elevato per la loro base utenti. Pertanto, è importante tenere presente che la maggior parte degli utenti vedrà la versione Container Query dell'interfaccia utente. E per il 10% di utenti che non lo fanno, non è come se vivrà un'esperienza inaccessibile. Quando seguono questa strategia, nel peggiore dei casi questi utenti vedranno il layout predefinito o "per dispositivi mobili" di alcuni componenti, che non è la fine del mondo.

Quando si tratta di scendere a compromessi, è buona norma eseguire l'ottimizzazione per la maggior parte dei tuoi utenti, invece di adottare un approccio con il minimo comune denominatore che offra a tutti gli utenti un'esperienza coerente, ma inferiore alla media.

Quindi, prima di presumere che non sia possibile utilizzare le query container a causa della mancanza di supporto dei browser, dedica del tempo a considerare l'esperienza se scegliessi di adottarle. Il compromesso potrebbe valere la pena, anche senza i fallback.

Prospettive future

Ci auguriamo che questo post ti abbia convinto che ora è possibile utilizzare le query container in produzione e che non devi aspettare anni prima che tutti i browser non supportati scompaiano completamente.

Anche se la strategia qui descritta richiede un po' di lavoro extra, dovrebbe essere abbastanza semplice e diretta da consentire alla maggior parte delle persone di adottarla sui propri siti. Detto questo, c'è sicuramente spazio per renderla ancora più facile da adottare. Un'idea è quella di consolidare molte delle diverse parti in un unico componente, ottimizzato per un framework o uno stack specifico, che gestisca tutto il lavoro di collante al posto tuo. Se crei qualcosa di simile, faccelo sapere e potremo aiutarti a promuoverlo.

Infine, oltre alle query sui container, ci sono tantissime fantastiche funzionalità CSS e UI che ora sono interoperabili in tutti i principali motori dei browser. Cerchiamo di capire insieme come community come possiamo usare queste funzionalità ora, in modo che i nostri utenti possano trarne vantaggio.