Containerabfragen jetzt verwenden

Vor Kurzem hat Chris Coyier in einem Blogpost die Frage gestellt:

Containerabfragen werden jetzt in allen Browser-Engines unterstützt. Warum nutzen nicht mehr Entwickler sie?

Chris in seinem Beitrag listet eine Reihe möglicher Gründe auf, z. B. mangelndes Bewusstsein, alte Gewohnheiten sterben hart. Es gibt jedoch einen besonderen Grund, der besonders auffällt.

Einige Entwickler geben an, dass sie jetzt Containerabfragen verwenden möchten, sind aber der Meinung, dass dies nicht möglich ist, da sie noch ältere Browser unterstützen müssen.

Wie Sie vielleicht schon im Titel vermutet haben, glauben wir, dass es für die meisten Entwickler möglich ist, Containerabfragen jetzt – in der Produktion – zu verwenden, selbst wenn Sie ältere Browser unterstützen müssen. In diesem Beitrag zeigen wir Ihnen, wie wir Ihnen dabei helfen können.

Ein pragmatischer Ansatz

Wenn Sie jetzt Containerabfragen in Ihrem Code verwenden möchten, die Darstellung aber in allen Browsern gleich sein soll, können Sie ein JavaScript-basiertes Fallback für Browser implementieren, die keine Containerabfragen unterstützen.

Die Frage lautet dann: Wie umfassend sollte das Fallback sein?

Wie bei jedem Alternativen besteht die Herausforderung darin, ein ausgewogenes Verhältnis zwischen Nützlichkeit und Leistung zu finden. Bei CSS-Funktionen ist es häufig nicht möglich, die vollständige API zu unterstützen. Weitere Informationen dazu finden Sie hier. Sie können jedoch weit kommen, indem Sie die Kernfunktionen ermitteln, die die meisten Entwickler verwenden möchten, und dann das Fallback speziell für diese Funktionen optimieren.

Aber welche Kernfunktionalität wünschen sich die meisten Entwickler für Containerabfragen? Um diese Frage zu beantworten, überlegen Sie, wie die meisten Entwickler derzeit responsive Websites mit Medienabfragen erstellen.

So gut wie alle modernen Designsysteme und Komponentenbibliotheken sind nach Mobile-First-Prinzipien standardisiert, die mithilfe vordefinierter Haltepunkte wie SM, MD, LG und XL implementiert wurden. Komponenten sind standardmäßig so optimiert, dass sie auf kleinen Bildschirmen gut dargestellt werden. Stile werden dann bedingt übereinandergelegt, um einen festen Satz größerer Bildschirmbreiten zu unterstützen. Beispiele dazu finden Sie in der Dokumentation zu Bootstrap und Tailwind.

Dieser Ansatz ist für containerbasierte Designsysteme genauso relevant wie für auf Darstellungsbereich basierende Designsysteme, denn in den meisten Fällen ist für Designer nicht die Größe des Bildschirms oder des Darstellungsbereichs relevant, sondern es kommt darauf an, wie viel Platz der Komponente im Kontext, in dem sie platziert wurde, zur Verfügung steht. Anders ausgedrückt: Statt sich die Haltepunkte auf den gesamten Darstellungsbereich beziehen (und auf die gesamte Seite anzuwenden), werden die Haltepunkte auf bestimmte Inhaltsbereiche angewendet, z. B. Seitenleisten, modale Dialogfelder oder Post-Textkörper.

Wenn Sie in der Lage sind, mit den Einschränkungen eines Mobile-First-, Haltepunkt-basierten Ansatzes zu arbeiten (wie es die meisten Entwickler derzeit tun), ist die Implementierung eines containerbasierten Fallbacks für diesen Ansatz erheblich einfacher als die Implementierung eines vollständigen Supports für jede einzelne Containerabfragefunktion.

Im nächsten Abschnitt wird genau erklärt, wie dies funktioniert. Außerdem erhalten Sie eine detaillierte Anleitung, die Ihnen zeigt, wie Sie das Tag auf einer vorhandenen Website implementieren.

Funktionsweise

Schritt 1: Komponentenstile aktualisieren, sodass @container-Regeln anstelle von @media-Regeln verwendet werden

Ermitteln Sie in diesem ersten Schritt alle Komponenten auf Ihrer Website, von denen Sie glauben, dass sie von einer containerbasierten und nicht einer Darstellungsgröße profitieren würden.

Es empfiehlt sich, mit nur einer oder zwei Komponenten zu beginnen, um zu sehen, wie diese Strategie funktioniert. Wenn Sie jedoch alle Komponenten auf containerbasierte Stile umstellen möchten, ist das auch kein Problem. Das Tolle an dieser Strategie ist, dass Sie sie bei Bedarf schrittweise anwenden können.

Sobald Sie die Komponenten identifiziert haben, die Sie aktualisieren möchten, müssen Sie jede @media-Regel im CSS-Code dieser Komponenten in eine @container-Regel ändern. Sie können die Bedingungen für die Größe unverändert lassen.

Wenn Ihr CSS bereits eine Reihe vordefinierter Haltepunkte verwendet, können Sie diese weiterhin genau wie definiert verwenden. Wenn Sie noch keine vordefinierten Haltepunkte verwenden, müssen Sie Namen für sie definieren. Darauf wird später in JavaScript in Schritt 2 verwiesen.

Hier sehen Sie ein Beispiel für Stile für eine .photo-gallery-Komponente, die standardmäßig aus einer einzelnen Spalte besteht. Dann wird der Stil so aktualisiert, dass er in den Haltepunkten MD bzw. XL zwei bzw. drei Spalten enthält:

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

Wenn Sie diese Komponentenstile von @media- in @container-Regeln ändern möchten, führen Sie in Ihrem Code die Funktion „Suchen und ersetzen“ durch:

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

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

Nachdem Sie die Stile Ihrer Komponenten von @media-Regeln zu haltepunktbasierten @container-Regeln geändert haben, müssen Sie im nächsten Schritt die Containerelemente konfigurieren.

Schritt 2: Containerelemente zum HTML-Code hinzufügen

Im vorherigen Schritt wurden Komponentenstile definiert, die auf der Größe eines Containerelements basieren. Im nächsten Schritt definieren Sie, auf welche Elemente auf Ihrer Seite die Containerelemente liegen, auf deren Größe die @container-Regeln bezogen sind.

Sie können jedes Element als Containerelement in CSS deklarieren, indem Sie die container-type-Eigenschaft auf size oder inline-size setzen. Wenn Ihre Containerregeln breit sind, sollten Sie im Allgemeinen inline-size verwenden.

Stellen Sie sich eine Website mit der folgenden grundlegenden HTML-Struktur vor:

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

Fügen Sie Ihrem CSS die folgende Regel hinzu, um die Elemente .sidebar und .content in diesen Website-containers zu machen:

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

Für Browser, die Containerabfragen unterstützen, benötigen Sie lediglich dieses CSS, um die im vorherigen Schritt definierten Komponenten-Stile relativ zum Hauptinhaltsbereich oder zur Seitenleiste zu machen, je nachdem, in welchem Element sie sich befinden.

Bei Browsern, die Containerabfragen nicht unterstützen, sind jedoch zusätzliche Schritte erforderlich.

Sie müssen Code hinzufügen, der erkennt, wenn sich die Größe der Containerelemente ändert, und dann das DOM basierend auf diesen Änderungen so aktualisieren, dass sich Ihr CSS-Code einbinden lässt.

Glücklicherweise ist der dazu erforderliche Code minimal und kann vollständig in eine gemeinsam genutzte Komponente abstrahiert werden, die Sie auf jeder Website und in jedem Inhaltsbereich verwenden können.

Mit dem folgenden Code wird ein wiederverwendbares <responsive-container>-Element definiert, das automatisch auf Größenänderungen achtet und Haltepunktklassen hinzufügt, die von deinem CSS-Code zum Design verwendet werden können:

// 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);

Mit diesem Code wird ein ResizeObserver erstellt, der automatisch auf Größenänderungen an allen <responsive-container>-Elementen im DOM wartet. Wenn die Größenänderung mit einer der definierten Haltepunktgrößen übereinstimmt, wird eine Klasse mit diesem Haltepunktnamen zum Element hinzugefügt (und entfernt, wenn die Bedingung nicht mehr erfüllt wird).

Wenn beispielsweise der width-Wert des <responsive-container>-Elements zwischen 768 und 1.024 Pixeln liegt (basierend auf den im Code festgelegten Standardhaltepunktwerten), werden die Klassen SM und MD hinzugefügt:

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

Mit diesen Klassen können Sie Fallback-Stile für Browser definieren, die keine Containerabfragen unterstützen (siehe Schritt 3: Fallback-Stile zum CSS-Code hinzufügen).

Um den vorherigen HTML-Code so zu aktualisieren, dass dieses Containerelement verwendet wird, ändern Sie die <div>-Elemente der Seitenleiste und des Hauptinhalts in <responsive-container>-Elemente:

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

In den meisten Fällen können Sie das <responsive-container>-Element einfach ohne Anpassungen verwenden. Wenn Sie es jedoch anpassen müssen, sind die folgenden Optionen verfügbar:

  • Benutzerdefinierte Haltepunktgrößen:In diesem Code werden Standard-Haltepunktklassen und Größen mit Mindestbreite verwendet. Sie können diese Standardgrößen beliebig ändern. Mit dem Attribut breakpoints können Sie diese Werte auch für einzelne Elemente überschreiben.
  • Benannte Container: Dieser Code unterstützt auch benannte Container durch Übergeben eines name-Attributs. Dies kann wichtig sein, wenn Sie Containerelemente verschachteln müssen. Weitere Informationen finden Sie im Abschnitt „Einschränkungen“.

Im folgenden Beispiel werden diese beiden Konfigurationsoptionen festgelegt:

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

Stellen Sie beim Bündeln dieses Codes sicher, dass Sie die Feature-Erkennung und das dynamische import() verwenden, um ihn nur zu laden, wenn der Browser keine Containerabfragen unterstützt.

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

Schritt 3: Fallback-Stile zu CSS hinzufügen

Der letzte Schritt bei dieser Strategie besteht darin, Fallback-Stile für Browser hinzuzufügen, die die in den @container-Regeln definierten Stile nicht erkennen. Duplizieren Sie dazu diese Regeln mithilfe der Haltepunktklassen, die für die <responsive-container>-Elemente festgelegt werden.

Wir bleiben bei dem .photo-gallery-Beispiel oben. Die Fallback-Stile für die beiden @container-Regeln könnten wie folgt aussehen:

/* 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 diesem Code gibt es für jede @container-Regel eine äquivalente Regel, die bedingt mit dem <responsive-container>-Element übereinstimmt, wenn die entsprechende Haltepunktklasse vorhanden ist.

Der Teil des Selektors, der mit dem <responsive-container>-Element übereinstimmt, ist in einen funktionalen Pseudoklassenselektor :where() eingebunden, damit die Spezifität des Fallback-Selektors der Spezifität des ursprünglichen Selektors in der @container-Regel entspricht.

Jede Fallback-Regel ist außerdem in eine @supports-Deklaration umschlossen. Dies ist zwar nicht unbedingt notwendig, damit das Fallback funktioniert, aber der Browser ignoriert diese Regeln vollständig, wenn er Containerabfragen unterstützt. Dadurch kann allgemein die Leistung des Stilabgleichs verbessert werden. Außerdem können Build-Tools oder CDNs diese Deklarationen entfernen, wenn bekannt ist, dass der Browser Containerabfragen unterstützt und diese Fallback-Stile nicht benötigt.

Der größte Nachteil dieser Fallback-Strategie besteht darin, dass die Stildeklaration zweimal wiederholt werden muss, was mühsam und fehleranfällig ist. Wenn Sie jedoch einen CSS-Präprozessor verwenden, können Sie dies in ein Mixin abstrahieren, das sowohl die @container-Regel als auch den Fallback-Code für Sie generiert. Hier ein Beispiel mit 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();
    }
  }
}

Sobald Sie dieses Mixin haben, könnten Sie die ursprünglichen .photo-gallery-Komponentenstile in etwa so aktualisieren, wodurch die Duplizierung vollständig entfällt:

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

So einfach ist das.

Zusammenfassung

Hier noch einmal kurz, wie Sie Ihren Code so aktualisieren, dass Containerabfragen jetzt mit einem browserübergreifenden Fallback verwendet werden.

  1. Identifizieren Sie Komponenten, die Sie relativ zu ihrem Container gestalten möchten, und aktualisieren Sie die @media-Regeln im CSS-Code, um @container-Regeln zu verwenden. Falls noch nicht geschehen, sollten Sie außerdem eine Reihe von Haltepunktnamen standardisieren, damit sie den Größenbedingungen in Ihren Containerregeln entsprechen.
  2. Fügen Sie den JavaScript-Code für das benutzerdefinierte <responsive-container>-Element und dann das <responsive-container>-Element zu allen Inhaltsbereichen auf Ihrer Seite hinzu, zu denen die Komponenten relativ sein sollen.
  3. Um ältere Browser zu unterstützen, fügen Sie Ihrem CSS Fallback-Stile hinzu, die mit den Haltepunktklassen abgleichen, die automatisch zu den <responsive-container>-Elementen im HTML-Code hinzugefügt werden. Idealerweise sollten Sie einen CSS-Präprozessor-Mixin verwenden, damit Sie nicht dieselben Stile zweimal schreiben müssen.

Das Tolle an dieser Strategie ist, dass sie einmalig Kosten für die Einrichtung verursachen. Danach ist jedoch kein zusätzlicher Aufwand erforderlich, um neue Komponenten hinzuzufügen und containerrelative Stile für sie zu definieren.

In Aktion sehen

Am besten lässt sich das Zusammenspiel dieser Schritte nachvollziehen, wenn Sie sich eine Demo davon in Aktion ansehen.

Video, in dem ein Nutzer mit der Demowebsite für Containerabfragen interagiert. Der Nutzer ändert die Größe der Inhaltsbereiche so, dass die Stile der Komponenten entsprechend der Größe des Inhaltsbereichs aktualisiert werden, in dem sie enthalten sind.

Diese Demo ist eine aktualisierte Version einer Website, die 2019 erstellt wurde (bevor es Containerabfragen gab), um zu veranschaulichen, warum Containerabfragen für das Erstellen wirklich responsiver Komponentenbibliotheken unerlässlich sind.

Da auf dieser Website bereits Stile für eine Reihe von „responsiven Komponenten“ definiert waren, war dies ein idealer Kandidat, um die hier eingeführte Strategie auf einer nicht trivialen Website zu testen. Es stellte sich heraus, dass die Aktualisierung ziemlich einfach war und fast keine Änderungen am ursprünglichen Stil der Website erforderlich waren.

Sie können sich den vollständigen Demo-Quellcode auf GitHub ansehen. Beachten Sie dabei auch die CSS-Elemente der Demokomponente, um zu sehen, wie die Fallback-Stile definiert sind. Wenn Sie nur das Fallback-Verhalten testen möchten, können Sie eine Nur-Fallback-Demo verwenden, in der genau diese Variante enthalten ist – selbst in Browsern, die Containerabfragen unterstützen.

Einschränkungen und potenzielle Verbesserungen

Wie bereits zu Beginn dieses Posts erwähnt, funktioniert die hier beschriebene Strategie bei den meisten Anwendungsfällen, die für Entwickler bei Containerabfragen relevant sind, gut.

Allerdings gibt es einige komplexere Anwendungsfälle, die mit dieser Strategie bewusst nicht umgesetzt werden sollen. Im Folgenden werden wir sie genauer untersuchen:

Container-Abfrageeinheiten

In der Spezifikation für Containerabfragen wird eine Anzahl von neuen Einheiten festgelegt, die alle in Relation zur Größe des Containers sind. Obwohl die meisten responsiven Designs in einigen Fällen nützlich sein können, kann sie wahrscheinlich durch vorhandene Methoden wie Prozentsätze oder die Verwendung von Raster- oder flexiblen Layouts realisiert werden.

Sollten Sie jedoch Container-Abfrageeinheiten verwenden müssen, können Sie diese mithilfe von benutzerdefinierten Properties ganz einfach unterstützen. Genauer gesagt, indem Sie wie folgt eine benutzerdefinierte Eigenschaft für jede Einheit definieren, die auf dem Containerelement verwendet wird:

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

Wenn Sie dann auf die Container-Abfrageeinheiten zugreifen müssen, verwenden Sie diese Attribute anstelle der Einheit selbst:

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

Legen Sie dann die Werte für diese benutzerdefinierten Eigenschaften im Containerelement innerhalb des ResizeObserver-Callbacks fest, damit ältere Browser unterstützt werden.

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

    // ...
  }
}

Auf diese Weise können Sie diese Werte von JavaScript an CSS übergeben und haben dann die volle Leistung von CSS (z. B. calc(), min(), max(), clamp()), um sie nach Bedarf zu bearbeiten.

Unterstützung logischer Eigenschaften und Schreibmodus

Möglicherweise ist Ihnen in einigen dieser CSS-Beispiele in den @container-Deklarationen inline-size statt width aufgefallen. Vielleicht haben Sie auch schon die neuen cqi- und cqb-Anzeigenblöcke (für Inline- bzw. Blockgrößen) bemerkt. Diese neuen Funktionen spiegeln den Wechsel von CSS zu logischen Eigenschaften und Werten statt auf physischen oder Richtungswerten wider.

Leider melden APIs wie Resize Observer immer noch Werte in width und height. Wenn Ihre Designs also Flexibilität bei logischen Eigenschaften benötigen, müssen Sie dies selbst herausfinden.

Es ist zwar möglich, den Schreibmodus z. B. mit getComputedStyle() über das Containerelement abzurufen, dies ist jedoch kostenpflichtig, und es gibt keine gute Möglichkeit festzustellen, ob sich der Schreibmodus ändert.

Aus diesem Grund empfiehlt es sich, für das <responsive-container>-Element selbst eine Schreibmoduseigenschaft zu akzeptieren, die der Websiteinhaber nach Bedarf festlegen und aktualisieren kann. Um dies zu implementieren, gehen Sie wie im vorherigen Abschnitt beschrieben vor und tauschen width und height nach Bedarf aus.

Verschachtelte Container

Mit dem Attribut container-name können Sie einem Container einen Namen geben, auf den Sie dann in einer @container-Regel verweisen können. Benannte Container sind nützlich, wenn Sie Container haben, die in Containern verschachtelt sind, und bestimmte Regeln benötigen, um nur bestimmte Container (nicht nur den nächstgelegenen Ancestor-Container) abzugleichen.

Bei der hier beschriebenen Fallback-Strategie wird die Nachfolgerkombination verwendet, um Elemente zu gestalten, die bestimmten Haltepunktklassen entsprechen. Dies kann bei verschachtelten Containern fehlschlagen, da beliebig viele Haltepunktklassen von mehreren Containerelement-Ancestors gleichzeitig mit einer bestimmten Komponente übereinstimmen können.

Hier gibt es beispielsweise zwei <responsive-container>-Elemente, die die .photo-gallery-Komponente umschließen. Da der äußere Container jedoch größer als der innere Container ist, wurden unterschiedliche Haltepunktklassen hinzugefügt.

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

In diesem Beispiel wirken sich die Klassen MD und LG im äußeren Container auf die Stilregeln aus, die der Komponente .photo-gallery entsprechen. Diese entspricht nicht dem Verhalten von Containerabfragen, da sie nur mit dem nächsten Ancestor-Container abgeglichen werden.

Sie haben zwei Möglichkeiten:

  1. Benennen Sie alle Container, die Sie verschachteln, und achten Sie darauf, dass den Haltepunktklassen dieser Containername vorangestellt wird, um Konflikte zu vermeiden.
  2. Verwenden Sie in den Fallback-Selektoren den untergeordneten Kombinator anstelle des untergeordneten Kombinators. Dies ist etwas eingeschränkter.

Der Abschnitt verschachtelte Container der Demowebsite enthält ein Beispiel für die Verwendung benannter Container sowie das Sass-Mixin, das im Code zum Generieren der Fallback-Stile für benannte und unbenannte @container-Regeln verwendet wird.

Was ist mit Browsern, die :where(), benutzerdefinierte Elemente und die Funktion zum Anpassen der Größe des Beobachters nicht unterstützen?

Auch wenn diese APIs relativ neu zu sein scheinen, werden sie alle seit mehr als drei Jahren in allen Browsern unterstützt und sind alle Teil der umfassenden Verfügbarkeit von Baseline.

Sofern Sie keine Daten haben, die darauf hinweisen, dass ein erheblicher Teil der Besucher Ihrer Website Browser verwendet, die eine dieser Funktionen nicht unterstützen, gibt es keinen Grund, sie ohne Fallback frei zu nutzen.

Selbst dann funktioniert in diesem speziellen Anwendungsfall im schlimmsten Fall, dass das Fallback bei einem sehr kleinen Prozentsatz Ihrer Nutzer nicht funktioniert. Für sie wird dann die Standardansicht und keine für die Containergröße optimierte Ansicht angezeigt.

Die Funktionalität der Website sollte auch weiterhin funktionieren und darauf kommt es an.

Warum nicht einfach ein Polyfill für Containerabfragen verwenden?

CSS-Funktionen sind berühmt schwierig zu polyfillr und erfordern im Allgemeinen, den gesamten CSS-Parser des Browsers und die Kaskadenlogik in JavaScript neu zu implementieren. Daher müssen CSS-Polyfill-Autoren viele Kompromisse eingehen, die fast immer mit zahlreichen Funktionseinschränkungen und erheblichen Leistungseinbußen verbunden sind.

Aus diesen Gründen raten wir im Allgemeinen von der Verwendung von CSS-Polyfills in der Produktion ab, einschließlich des container-query-polyfill von Google Chrome Labs, das nicht mehr verwaltet wird und hauptsächlich zu Demozwecken gedacht ist.

Die hier beschriebene Fallback-Strategie weist weniger Einschränkungen auf, erfordert weitaus weniger Code und funktioniert deutlich besser als jede Containerabfrage-Polyfill, die es je geben könnte.

Müssen Sie überhaupt ein Fallback für ältere Browser implementieren?

Wenn Sie wegen einer der hier genannten Einschränkungen Bedenken haben, sollten Sie sich fragen, ob Sie überhaupt ein Fallback implementieren müssen. Schließlich können Sie diese Einschränkungen am einfachsten vermeiden, indem Sie die Funktion ohne Fallbacks verwenden. Ehrlich gesagt kann das in vielen Fällen eine durchaus vernünftige Entscheidung sein.

Laut caniuse.com werden Containerabfragen von 90% der Internetnutzer weltweit unterstützt. Für viele Nutzer, die diesen Post lesen, ist die Zahl bei ihren Nutzern wahrscheinlich auch deutlich höher. Beachten Sie daher, dass die meisten Nutzer die Containerabfrageversion Ihrer UI sehen. Und für die 10% der Nutzer, die das nicht tun, ist das auch kein Problem. Wenn diese Strategie angewendet wird, wird den Nutzern im schlimmsten Fall das Standardlayout, also das "mobile" Layout für einige Komponenten, angezeigt, was kein Ende der Welt ist.

Wenn Sie Kompromisse eingehen, empfiehlt es sich, eine Optimierung für die Mehrheit Ihrer Nutzer vorzunehmen, anstatt einen Ansatz mit dem niedrigsten gemeinsamen Nenner zu verwenden, der allen Nutzern eine konsistente, aber unterdurchschnittliche Nutzererfahrung bietet.

Bevor Sie also davon ausgehen, dass Sie aufgrund fehlender Browserunterstützung keine Containerabfragen verwenden können, sollten Sie sich die Zeit nehmen, wie die Verwendung aussehen würde, wenn Sie sich dafür entscheiden würden. Der Kompromiss kann sich lohnen, auch wenn keine Fallbacks vorhanden sind.

Aussichten

Ich hoffe, dieser Post hat Sie davon überzeugt, dass es jetzt möglich ist, Containerabfragen in der Produktion zu verwenden, und dass Sie nicht jahrelang warten müssen, bis alle nicht unterstützten Browser vollständig verschwinden.

Die hier beschriebene Strategie erfordert zwar zusätzlichen Aufwand, sie sollte aber so einfach und verständlich sein, dass sie von den meisten Nutzern auf ihren Websites übernommen werden kann. Dennoch gibt es sicherlich Raum, um die Einführung zu erleichtern. Eine Idee wäre, viele der verschiedenen Teile in einer einzigen, für ein bestimmtes Framework oder einen bestimmten Stack optimierten Komponente zu konsolidieren, die die gesamte Klebarbeit für Sie übernimmt. Wenn Sie eine solche Lösung entwickeln, teilen Sie uns dies bitte mit, damit wir sie bewerben können.

Abgesehen von Containerabfragen gibt es außerdem zahlreiche tolle CSS- und UI-Funktionen, die in allen gängigen Browser-Engines interoperabel sind. Lassen Sie uns als Community herausfinden, wie wir diese Funktionen jetzt tatsächlich nutzen können, damit unsere Nutzer davon profitieren.