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?
In Chriss Beitrag wird eine Reihe möglicher Gründe aufgeführt, 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 was ist die „Kernfunktion“, die sich die meisten Entwickler für Containerabfragen wünschen? 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 und mithilfe vordefinierter Haltepunkte wie SM
, MD
, LG
und XL
implementiert. 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 in diesen Komponenten ändern. CSS zu einer @container
-Regel hinzufügen.
Hier ein Beispiel dafür, wie dies auf einer .photo-gallery
-Komponente aussehen könnte, die standardmäßig aus einer Spalte besteht und dann @media
-Regeln verwendet, um das Layout zu aktualisieren, sodass es in den MD- bzw. XL-Haltenpunkten zwei bzw. drei Spalten wird:
.photo-gallery {
display: grid;
grid-template-columns: 1fr;
}
/* Styles for the `MD` breakpoint */
@media (min-width: 800px) {
.photo-gallery {
grid-template-columns: 1fr 1fr;
}
}
/* Styles for the `XL` breakpoint */
@media (min-width: 1200px) {
.photo-gallery {
grid-template-columns: 1fr 1fr 1fr;
}
}
Wenn Sie die Komponente „.photo-gallery
“ zur Verwendung von @container
-Regeln aktualisieren möchten, ersetzen Sie zuerst im CSS den String @media
durch den String @container
. Die Grammatik dieser beiden Regeln ist so ähnlich, dass Sie in vielen Fällen möglicherweise nur diese Änderung ändern müssen.
Je nach Design deiner Website musst du möglicherweise auch die Größenbedingung aktualisieren, insbesondere wenn die @media
-Regeln deiner Website bestimmte Annahmen darüber treffen, wie viel Platz für bestimmte Komponenten in verschiedenen Größen des Darstellungsbereichs zur Verfügung steht.
Wenn im vorherigen Beispiel bei den Stilen für das CSS-Format .photo-gallery
an den Haltepunkten MD
und XL
davon ausgegangen wird, dass an diesen Haltepunkten eine 200 Pixel breite Seitenleiste angezeigt wird, sollten die Größenbedingungen für die @container
-Regeln etwa 200 Pixel kleiner sein, vorausgesetzt, der „Container“ für die Komponente .photo-gallery
enthält keine Seitenleiste.
Wenn Sie die CSS-Elemente .photo-gallery
von @media
-Regeln in @container
-Regeln umwandeln, sind die folgenden Änderungen erforderlich:
/* Before, using the original breakpoint sizes: */
@media (min-width: 800px) { /* ... */ }
@media (min-width: 1200px) { /* ... */ }
/* After, with the breakpoint sizes reduced by 200px: */
@container (min-width: 600px) { /* ... */ }
@container (min-width: 1000px) { /* ... */ }
Beachten Sie, dass Sie die Stile innerhalb des Deklarationsblocks nicht ändern müssen, da diese Stile angeben, wie die Komponente aussieht, und nicht, wann bestimmte Stile angewendet werden sollen.
Nachdem Sie die Stile Ihrer Komponenten von @media
-Regeln zu @container
-Regeln geändert haben, können 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, welche Elemente auf Ihrer Seite die Containerelemente sein sollen, 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-Containern 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 auf der Grundlage dieser Ä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 Größenänderungen erkennt und Haltepunktklassen hinzufügt, auf denen Ihr CSS-Stil basierend auf den Stilen gestalten kann:
// A mapping of default breakpoint class names and min-width sizes.
// Redefine these (or add more) as needed based on your site's design.
const defaultBreakpoints = {SM: 400, MD: 600 LG: 800, XL: 1000};
// 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 600 und 800 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='{"bp4":400,"bp5":500,"bp6":600,"bp7":700,"bp8":800,"bp9":900,"bp10":1000}'>
</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.
Wenn wir noch auf das .photo-gallery
-Beispiel zurückkommen, können die Fallback-Stile für die beiden @container
-Regeln so aussehen:
/* Container query styles for the `MD` breakpoint. */
@container (min-width: 600px) {
.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: 1000px) {
.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': 400px,
'MD': 600px,
'LG': 800px,
'XL': 1000px,
);
@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
Um es zusammenzufassen: So aktualisieren Sie Ihren Code, um Containerabfragen jetzt mit einem browserübergreifenden Fallback zu verwenden.
- 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. - Fügen Sie den JavaScript-Code für das benutzerdefinierte
<responsive-container>
-Element und anschließend das<responsive-container>
-Element in alle Inhaltsbereiche auf Ihrer Seite ein, zu denen Ihre Komponenten relativ sein sollen. - Zur Unterstützung älterer Browser 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.
<ph type="x-smartling-placeholder">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 der perfekte 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`);
// ...
}
}
So können Sie effektiv um diese Werte von JavaScript in CSS zu übertragen, 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 Container in Containern verschachtelt sind und bestimmte Regeln erforderlich sind, damit nur bestimmte Container (nicht nur der nächstgelegene Ancestor-Container) übereinstimmen.
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:
- Benennen Sie alle Container, die Sie verschachteln, und achten Sie darauf, dass den Haltepunktklassen dieser Containername vorangestellt wird, um Konflikte zu vermeiden.
- 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 ist dies in vielen Fällen eine durchaus vernünftige Entscheidung.
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 Sie sich an diese Strategie halten, sehen diese Nutzer im schlimmsten Fall die Standardeinstellung bzw. „mobile“. für manche Komponenten, was nicht das 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.
Aktualisierung (25. Juli 2024): Ursprüngliche Anleitung in Schritt 1 schlug vor, dass Medien- und Containerabfragen dieselben Größenbedingungen verwenden könnten. Das ist häufig der Fall, aber nicht immer. Einige Gründe haben wir zu Recht erwähnt. In der aktualisierten Anleitung wird dies jetzt klarer und es werden Beispielfälle aufgeführt, in denen die Größenbedingungen möglicherweise geändert werden müssen.
Aktualisierung (2. Juli 2024): Ursprünglich wurde in allen CSS-Codebeispielen Sass verwendet, um der endgültigen Empfehlung gerecht zu werden. Basierend auf dem Feedback von Lesern wurden die ersten CSS-Elemente auf einfaches CSS aktualisiert. Sass wird nur in den Codebeispielen verwendet, für die Mixins erforderlich sind.