Anfang 2017 präsentierte ich ein paar Workshops zum Thema CSS-Feature-Erkennung mit dem Titel CSS Feature Detection in 2017.
Ein Freund von mir, Justin Slack von New Media Labs, schickte mir kürzlich einen Link zur phänomenalen Erweiterung Feature Query Manager (verfügbar für Chrome und Firefox), von der nigerianischen Entwicklerin Ire Aderinokun. Dies schien eine perfekte Ergänzung zu meinem Workshop-Material zum Thema zu sein.
Als ich jedoch zu dem Material zurückkehrte, wurde mir bewusst, wie sehr meine Arbeit zu diesem Thema in den letzten 18 Monaten veraltet ist.
Die CSS-Landschaft hat einige tektonische Verschiebungen erfahren
- Der Atomic CSS-Ansatz, obwohl anfangs weitgehend verpönt, hat durch Bibliotheken wie Tailwind an Fahrt gewonnen und vielleicht die Aufnahme mehrerer neuer Utility-Klassen in Bootstrap 4 beeinflusst.
- CSS-in-JS explodierte in der Popularität, mit Styled Components an der Spitze der Bewegung.
- Die CSS Grid Layout-Spezifikation wurde von den Browserherstellern mit überraschender Geschwindigkeit übernommen und praktisch sofort als produktionsreif anerkannt.
Das Obige veranlasste mich, nicht nur mein bestehendes Material zu überarbeiten, sondern auch über den Zustand der CSS-Feature-Erkennung in den kommenden 18 Monaten nachzudenken.
Kurz gesagt
- ❓ Warum brauchen wir überhaupt CSS-Feature-Erkennung?
- 🛠️ Welche Möglichkeiten zur Feature-Erkennung sind gut (und welche nicht)?
- 🤖 Was hält die Zukunft für die CSS-Feature-Erkennung bereit?
Browserübergreifendes CSS
Wenn man mit CSS arbeitet, scheint eine der Hauptsorgen immer die inkonsistente Unterstützung von Funktionen in verschiedenen Browsern zu sein. Das bedeutet, dass CSS-Styling in meinen bevorzugten Browsern perfekt aussehen mag, aber in einem anderen Browser (vielleicht einem noch beliebteren) komplett kaputt sein kann.
Glücklicherweise ist der Umgang mit inkonsistenter Browserunterstützung trivial, dank einer Schlüsselfunktion im Design der CSS-Sprache selbst. Dieses Verhalten, das als Fehlertoleranz bezeichnet wird, bedeutet, dass Browser CSS-Code, den sie nicht verstehen, ignorieren. Dies steht im starken Gegensatz zu Sprachen wie JavaScript oder PHP, die die gesamte Ausführung stoppen, um einen Fehler auszugeben.

Die kritische Schlussfolgerung hier ist, dass, wenn wir unser CSS entsprechend schichten, Eigenschaften nur angewendet werden, wenn der Browser versteht, was sie bedeuten. Als Beispiel können Sie die folgende CSS-Regel einfügen, und der Browser wird sie einfach ignorieren – sie überschreibt die anfängliche gelbe Farbe, ignoriert aber den dritten unsinnigen Wert.
background-color: yellow;
background-color: blue; /* Overrides yellow */
background-color: aqy8godf857wqe6igrf7i6dsgkv; /* Ignored */
Um zu veranschaulichen, wie dies in der Praxis genutzt werden kann, beginne ich mit einer konstruierten, aber geradlinigen Situation
Ein Kunde kommt mit dem dringenden Wunsch auf Sie zu, eine Handlungsaufforderung (in Form eines Popups) auf seiner Homepage einzubauen. Mit Ihren fantastischen Frontend-Fähigkeiten können Sie schnell die aufdringlichste Popup-Nachricht erstellen, die die Welt je gesehen hat.
Leider stellt sich heraus, dass seine Frau eine alte Windows XP-Maschine mit Internet Explorer 8 besitzt. Sie sind schockiert zu erfahren, dass das, was sie sieht, nicht mehr im Entferntesten einem Popup ähnelt.
Aber! Wir erinnern uns, dass wir mit der Magie der CSS-Fehlertoleranz die Situation beheben können. Wir identifizieren alle kritischen Teile des Stylings (z. B. der Schatten ist nett zu haben, fügt aber nichts Nützliches für die Benutzerfreundlichkeit hinzu) und versehen den Kernstil mit Fallbacks.
Das bedeutet, dass unser CSS nun ungefähr so aussieht (die Überschreibungen sind zur besseren Übersichtlichkeit hervorgehoben)
.overlay {
background: grey;
background: rgba(0, 0, 0, 0.4);
border: 1px solid grey;
border: 1px solid rgba(0, 0, 0, 0.4);
padding: 64px;
padding: 4rem;
display: block;
display: flex;
justify-content: center; /* if flex is supported */
align-items: center; /* if flex is supported */
height: 100%;
width: 100%;
}
.popup {
background: white;
background-color: rgba(255, 255, 255, 1);
border-radius: 8px;
border: 1px solid grey;
border: 1px solid rgba(0, 0, 0, 0.4);
box-shadow:
0 7px 8px -4px rgba(0,0, 0, 0.2),
0 13px 19px 2px rgba(0, 0, 0, 0.14),
0 5px 24px 4px rgba(0, 0, 0, 0.12);
padding: 32px;
padding: 2rem;
min-width: 240px;
}
button {
background-color: #e0e1e2;
background-color: rgba(225, 225, 225, 1);
border-width: 0;
border-radius: 4px;
border-radius: 0.25rem;
box-shadow:
0 1px 3px 0 rgba(0,0,0,.2),
0 1px 1px 0 rgba(0,0,0,.14),
0 2px 1px -1px rgba(0,0,0,.12);
color: #5c5c5c;
color: rgba(95, 95, 95, 1);
cursor: pointer;
font-weight: bold;
font-weight: 700;
padding: 16px;
padding: 1rem;
}
button:hover {
background-color: #c8c8c8;
background-color: rgb(200,200,200);
}
Das obige Beispiel fällt generell unter den breiteren Ansatz der progressiven Verbesserung. Wenn Sie mehr über progressive Verbesserung erfahren möchten, schauen Sie sich die zweite Auflage von Aaron Gustafsons fantastischem Buch zu diesem Thema an, mit dem Titel Adaptive Web Design: Crafting Rich Experiences with Progressive Enhancement (2016).

Wenn Sie neu in der Frontend-Entwicklung sind, fragen Sie sich vielleicht, wie man überhaupt das Unterstützungsniveau spezifischer CSS-Eigenschaften kennt. Die kurze Antwort ist, dass Sie mit zunehmender Arbeit mit CSS diese mit der Zeit auswendig lernen. Es gibt jedoch ein paar Werkzeuge, die uns dabei helfen können.
- Can I Use ist ein weit verbreitetes Verzeichnis, das durchsuchbare, aktuelle Support-Matrizen für alle CSS-Funktionen enthält.
- Stylelint hat ein phänomenales Plugin namens No Unsupported Browser Features, das Fehler für nicht unterstützte CSS (definiert über Browserslist) entweder in Ihrem Editor selbst oder über einen Terminalbefehl findet.
- Es gibt verschiedene Tools wie BrowserStack oder Cross Browser Testing, die es Ihnen ermöglichen, Ihre Website remote in verschiedenen Browsern zu testen. Beachten Sie, dass es sich hierbei um kostenpflichtige Dienste handelt, obwohl BrowserStack eine kostenlose Stufe für Open-Source-Projekte anbietet.
Selbst mit all dem oben Genannten wird uns das Auswendiglernen der CSS-Unterstützung helfen, unser Styling von Anfang an zu planen und unsere Effizienz beim Schreiben zu steigern.
Grenzen der CSS-Fehlertoleranz
In der nächsten Woche meldet sich Ihr Kunde mit einer neuen Anfrage. Er möchte Feedback von Benutzern zu den zuvor vorgenommenen Änderungen an der Homepage erhalten – wieder mit einem Popup.
Wieder wird es im Internet Explorer 8 wie folgt aussehen
Da Sie dieses Mal proaktiver vorgehen, nutzen Sie Ihre neuen Fallback-Kenntnisse, um ein Basis-Styling zu erstellen, das im Internet Explorer 8 funktioniert, und progressive Stylings für alles andere. Leider stoßen wir immer noch auf ein Problem...
Um die Standard-Radio-Buttons durch ASCII-Herzen zu ersetzen, verwenden wir das Pseudo-Element ::before. Dieses Pseudo-Element wird jedoch im Internet Explorer 8 nicht unterstützt. Das bedeutet, dass das Herz-Icon nicht gerendert wird; die Eigenschaft display: none des Elements <input type="radio"> wird jedoch weiterhin im Internet Explorer 8 ausgelöst. Dies hat zur Folge, dass weder das Ersetzungsverhalten noch das Standardverhalten angezeigt werden.
Ein Dankeschön an John Faulds, der darauf hinwies, dass es tatsächlich möglich ist, das Pseudo-Element ::before im Internet Explorer 8 zum Laufen zu bringen, wenn man die offizielle Doppelpunkt-Syntax durch einen einzelnen Doppelpunkt ersetzt.
Kurz gesagt, wir haben eine Regel (display: none), deren Ausführung nicht an ihre eigene Unterstützung gebunden sein sollte (und somit an ihre eigene Fallback-Struktur), sondern an das Unterstützungsniveau eines völlig separaten CSS-Features (::before).

Für alle praktischen Zwecke besteht der übliche Ansatz darin, zu prüfen, ob es einfachere Lösungen gibt, die nicht auf ::before angewiesen sind. Um des Beispiels willen nehmen wir jedoch an, dass die obige Lösung nicht verhandelbar ist (und manchmal ist sie das auch).
User-Agent-Erkennung
Eine Lösung könnte darin bestehen, festzustellen, welchen Browser der Benutzer verwendet, und dann nur dann display: none anzuwenden, wenn sein Browser das Pseudo-Element ::before unterstützt.
Tatsächlich ist dieser Ansatz fast so alt wie das Web selbst. Er ist bekannt als User-Agent-Erkennung oder umgangssprachlich als Browser-Sniffing.
Normalerweise geschieht dies wie folgt
- Alle Browser fügen dem globalen window-Objekt eine JavaScript-Eigenschaft namens
navigatorhinzu, und dieses Objekt enthält eineuserAgent-String-Eigenschaft. - In meinem Fall lautet der
userAgent-String:Mozilla/5.0 (Windows NT10.0;Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.9 Safari/537.36. - Das Mozilla Developer Network bietet eine umfassende Liste, wie dies zur Bestimmung des Browsers verwendet werden kann.
- Wenn wir Chrome verwenden, sollte das Folgende `true` zurückgeben:
(navigator.userAgent.indexOf("chrome") !== -1). - Unter dem Abschnitt Internet Explorer auf MDN erhalten wir jedoch nur
Internet Explorer. IE fügt seinen Namen nicht im FormatBrowserName/VersionNumberein. - Glücklicherweise bietet der Internet Explorer seine eigene native Erkennung in Form von Conditional Comments.
Das bedeutet, dass das Einfügen des Folgenden in unser HTML ausreichen sollte
<!--[if lt IE 9]>
<style>
input {
display: block;
}
</style>
<![endif]-->
Dies bedeutet, dass das Obige angewendet wird, wenn der Browser eine Version des Internet Explorer unter Version 9 ist (IE 9 unterstützt ::before) – und damit die Eigenschaft display: none überschreibt.
Scheint einfach genug?
Leider traten im Laufe der Zeit einige kritische Fehler bei der User-Agent-Erkennung auf. So sehr, dass der Internet Explorer ab Version 10 keine Conditional Comments mehr unterstützt. Sie werden auch feststellen, dass im Link Mozilla Developer Network selbst Folgendes in einem orangefarbenen Warnhinweis steht:
Es sei noch einmal betont: Es ist sehr selten eine gute Idee, User-Agent-Sniffing zu verwenden. Sie finden fast immer einen besseren, breiter kompatiblen Weg, um Ihr Problem zu lösen!
Der größte Nachteil der User-Agent-Erkennung ist, dass die Browserhersteller ihre User-Agent-Strings im Laufe der Zeit aus folgenden Gründen gefälscht haben
- Entwickler fügt eine CSS-Funktion hinzu, die vom Browser nicht unterstützt wird.
- Entwickler fügt User-Agent-Erkennungs-Code hinzu, um Fallbacks für den Browser bereitzustellen.
- Der Browser fügt schließlich Unterstützung für diese spezielle CSS-Funktion hinzu.
- Der ursprüngliche User-Agent-Erkennungs-Code wird nicht aktualisiert, um dies zu berücksichtigen.
- Der Code zeigt immer den Fallback an, auch wenn der Browser die CSS-Funktion jetzt unterstützt.
- Der Browser verwendet eine gefälschte User-Agent-Zeichenkette, um den Benutzern das beste Erlebnis im Web zu bieten.
Darüber hinaus müssten wir, selbst wenn wir jeden Browsertyp und jede Version fehlerfrei ermitteln könnten, unsere User-Agent-Erkennung aktiv pflegen und aktualisieren, um den Stand der Feature-Unterstützung dieser Browser widerzuspiegeln (ganz zu schweigen von Browsern, die noch nicht einmal entwickelt wurden).
Es ist wichtig zu beachten, dass es, obwohl es oberflächliche Ähnlichkeiten zwischen Feature-Erkennung und User-Agent-Erkennung gibt, die Feature-Erkennung einen radikal anderen Ansatz verfolgt als die User-Agent-Erkennung. Laut dem Mozilla Developer Network tun wir im Wesentlichen Folgendes, wenn wir Feature-Erkennung verwenden:
- 🔎 Testen, ob ein Browser tatsächlich eine bestimmte Codezeile (oder Zeilen) aus HTML, CSS oder JavaScript ausführen kann.
- 💪 Ausführen einer spezifischen Aktion basierend auf dem Ergebnis dieses Tests.
Wir können uns auch an Wikipedia für eine formellere Definition wenden (Hervorhebung von mir)
Feature-Erkennung (auch Feature-Test) ist eine Technik, die in der Webentwicklung zur Handhabung von Unterschieden zwischen Laufzeitumgebungen (typischerweise Webbrowsern oder User Agents) verwendet wird, indem programmatisch nach Hinweisen getestet wird, ob die Umgebung bestimmte Funktionalitäten anbietet oder nicht. Diese Informationen werden dann verwendet, um die Anwendung auf irgendeine Weise anzupassen, um sie an die Umgebung anzupassen: um bestimmte APIs zu nutzen oder ein besseres Benutzererlebnis zu gestalten.
Obwohl diese Definition ein wenig esoterisch ist, hebt sie doch zwei wichtige Aspekte der Feature-Erkennung hervor:
- Feature-Erkennung ist eine Technik, im Gegensatz zu einem spezifischen Werkzeug oder einer Technologie. Das bedeutet, dass es verschiedene (gleichwertige) Wege gibt, Feature-Erkennung zu bewerkstelligen.
- Feature-Erkennung testet Code programmatisch. Das bedeutet, dass Browser tatsächlich ein Stück Code ausführen, um zu sehen, was passiert, anstatt lediglich Schlussfolgerungen zu ziehen oder es mit einem theoretischen Referenz-/Listenvergleich zu vergleichen, wie bei der User-Agent-Erkennung.

CSS-Feature-Erkennung mit @supports
Das Kernkonzept ist nicht zu fragen: „Was ist das für ein Browser?“ Es ist zu fragen: „Unterstützt Ihr Browser die Funktion, die ich verwenden möchte?“
—Rob Larson, The Uncertain Web: Web Development in a Changing Landscape (2014)
Die meisten modernen Browser unterstützen eine Reihe von nativen CSS-Regeln, die als CSS-bedingte Regeln bezeichnet werden. Diese ermöglichen es uns, bestimmte Bedingungen innerhalb des Stylesheets selbst zu testen. Die neueste Iteration (bekannt als Modul-Level 3) wird von der Cascading Style Sheets Working Group wie folgt beschrieben:
Dieses Modul enthält die Features von CSS für die bedingte Verarbeitung von Teilen von Style Sheets, bedingt durch die Fähigkeiten des Prozessors oder des Dokuments, auf das das Style Sheet angewendet wird. Es beinhaltet und erweitert die Funktionalität von CSS Level 2 [CSS21], die auf CSS Level 1 [CSS1] aufbaut. Die wichtigsten Erweiterungen im Vergleich zu Level 2 sind die Erlaubnis, bestimmte @-Regeln in „@media“ zu verschachteln, und die Hinzufügung der „@supports“-Regel für die bedingte Verarbeitung.
Wenn Sie @media, @document oder @import schon einmal verwendet haben, haben Sie bereits Erfahrung mit CSS-bedingten Regeln. Wenn Sie zum Beispiel CSS Media Queries verwenden, tun wir Folgendes:
- Wickeln Sie eine einzelne oder mehrere CSS-Deklarationen in einen Codeblock mit geschweiften Klammern
{ }. - Präfixieren Sie den Codeblock mit einer
@media-Abfrage mit zusätzlichen Informationen. - Fügen Sie einen optionalen Medientyp hinzu. Dies kann entweder
all,print,speechoder der häufig verwendetescreen-Typ sein. - Verketten Sie Ausdrücke mit
and/or, um den Geltungsbereich zu bestimmen. Wenn wir zum Beispiel(min-width: 300px) and (max-width: 800px)verwenden, löst dies die Abfrage aus, wenn die Bildschirmgröße breiter als 300 Pixel und kleiner als 800 Pixel ist.
Die Spezifikation der Feature-Abfragen (Editor-Entwurf) schreibt ein Verhalten vor, das praktischerweise dem obigen Beispiel ähnelt. Anstatt einen Abfrageausdruck zu verwenden, um eine Bedingung basierend auf der Bildschirmgröße festzulegen, schreiben wir einen Ausdruck, um unseren Codeblock entsprechend der CSS-Unterstützung eines Browsers zu beschränken (Hervorhebung von mir):
Die ‚@supports-Regel ermöglicht es, CSS zu konditionieren, je nachdem, ob die Implementierung CSS-Eigenschaften und -Werte unterstützt. Diese Regel macht es für Autoren wesentlich einfacher, neue CSS-Features zu nutzen und gute Fallbacks für Implementierungen bereitzustellen, die diese Features nicht unterstützen. Dies ist besonders wichtig für CSS-Features, die neue Layoutmechanismen bereitstellen, und für andere Fälle, in denen eine Reihe verwandter Stile von der Unterstützung der Eigenschaften abhängen muss.
Kurz gesagt, Feature-Abfragen sind ein kleines, integriertes CSS-Tool, das es uns ermöglicht, nur dann Code auszuführen (wie im obigen display: none-Beispiel), wenn ein Browser eine separate CSS-Funktion unterstützt – und ähnlich wie bei Media Queries können wir Ausdrücke verketten, wie zum Beispiel: @supports (display: grid) and ((animation-name: spin) or (transition: transform(rotate(360deg)).

Theoretisch sollten wir also Folgendes tun können:
@supports (::before) {
input {
display: none;
}
}
Leider scheint es, dass im obigen Beispiel die Eigenschaft display: none nicht ausgelöst wurde, obwohl Ihr Browser wahrscheinlich ::before unterstützt.
Das liegt daran, dass es einige Vorbehalte bei der Verwendung von @supports gibt
- Erstens unterstützen CSS-Feature-Abfragen nur CSS-Eigenschaften und keine CSS-Pseudo-Elemente wie
::before. - Zweitens sehen Sie, dass in unserem Beispiel oben die Bedingung
@supports (transform: scale(2)) and (animation-name: beat)korrekt ausgelöst wird. Wenn wir sie jedoch im Internet Explorer 11 testen (der sowohltransform: scale(2)als auchanimation-name: beatunterstützt), wird sie nicht ausgelöst. Was ist los? Kurz gesagt,@supportsist eine CSS-Funktion mit einer eigenen Support-Matrix.
CSS-Feature-Erkennung mit Modernizr
Glücklicherweise ist die Lösung recht einfach! Sie kommt in Form einer Open-Source-JavaScript-Bibliothek namens Modernizr, die ursprünglich von Faruk Ateş entwickelt wurde (obwohl sie jetzt einige ziemlich große Namen dahinter hat, wie Paul Irish von Chrome und Alex Sexton von Stripe).
Bevor wir uns mit Modernizr befassen, lassen Sie uns ein Thema ansprechen, das für viele Entwickler große Verwirrung stiftet (zum Teil wegen des Namens „Modernizr“ selbst). Modernizr transformiert Ihren Code nicht und aktiviert auch keine nicht unterstützten Funktionen auf magische Weise. Tatsächlich ist die einzige Änderung, die Modernizr an Ihrem Code vornimmt, das Anhängen spezifischer CSS-Klassen an Ihr <html>-Tag.
Das bedeutet, dass Sie am Ende etwas Ähnliches wie das Folgende erhalten könnten:
<html class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">
Das ist ein großes HTML-Tag! Es ermöglicht uns jedoch etwas sehr Mächtiges zu tun: die Verwendung von CSS-Nachfahrenselektoren, um bedingt CSS-Regeln anzuwenden.
Wenn Modernizr ausgeführt wird, verwendet es JavaScript, um zu erkennen, was der Browser des Benutzers unterstützt. Wenn er diese Funktion unterstützt, fügt Modernizr deren Namen als Klasse zum <html> hinzu. Alternativ, wenn der Browser die Funktion nicht unterstützt, versieht es die eingefügte Klasse mit dem Präfix no- (z. B. no-generatedcontent in unserem ::before-Beispiel). Das bedeutet, dass wir unsere bedingte Regel im Stylesheet wie folgt schreiben können:
.generatedcontent input {
display: none
}
Zusätzlich können wir die Verkettung von @supports-Ausdrücken in Modernizr wie folgt nachbilden:
/* default */
.generatedcontent input { }
/* 'or' operator */
.generatedcontent input, .csstransforms input { }
/* 'and' operator */
.generatedcontent.csstransformsinput { }
/* 'not' operator */
.no-generatedcontent input { }
Da Modernizr in JavaScript läuft (und keine nativen Browser-APIs verwendet), wird es praktisch von fast allen Browsern unterstützt. Das bedeutet, dass wir durch die Nutzung von Klassen wie generatedcontent und csstransforms alle unsere Grundlagen für Internet Explorer 8 abdecken können, während wir gleichzeitig den neuesten Browsern die aktuellsten CSS-Styles bereitstellen.
Es ist wichtig zu beachten, dass seit der Veröffentlichung von Modernizr 3.0 keine Standarddatei modernizr.js mehr heruntergeladen werden kann mit allem außer der Spüle. Stattdessen müssen wir unseren eigenen benutzerdefinierten Modernizr-Code über ihren Wizard generieren (zum Kopieren oder Herunterladen). Dies ist höchstwahrscheinlich eine Reaktion auf den zunehmenden globalen Fokus auf Web-Performance in den letzten Jahren. Das Überprüfen von mehr Funktionen führt zu mehr Ladezeit, daher möchte Modernizr, dass wir nur das überprüfen, was wir benötigen.
Sollte ich also immer Modernizr verwenden?
Angesichts der Tatsache, dass Modernizr praktisch in allen Browsern unterstützt wird, gibt es dann überhaupt noch einen Sinn, CSS-Feature-Abfragen zu verwenden? Ironischerweise würde ich nicht nur sagen, dass wir das sollten, sondern dass Feature-Abfragen immer noch unser erster Anlaufpunkt sein sollten.
Erstens und vor allem ist die Tatsache, dass Modernizr nicht direkt in die Browser-API integriert ist, sein größter Vorteil – es verlässt sich nicht auf die Verfügbarkeit einer bestimmten Browser-API. Dieser Vorteil hat jedoch seinen Preis, und dieser Preis ist zusätzlicher Overhead für etwas, das die meisten Browser standardmäßig über @supports unterstützen – insbesondere, wenn Sie diesen zusätzlichen Overhead wahllos an alle Benutzer liefern, um eine kleine Anzahl von Randbenutzern zu bedienen. Es ist wichtig zu beachten, dass der Internet Explorer 8 im obigen Beispiel derzeit nur 0,18% der globalen Nutzung ausmacht).

Im Vergleich zur leichten Berührung von @supports hat Modernizr die folgenden Nachteile:
- Der Ansatz, der der Entwicklung von Modernizr zugrunde liegt, basiert auf der Annahme, dass Modernizr „von Anfang an dazu gedacht war, letztendlich unnötig zu werden.“.
- In den meisten Fällen muss Modernizr Render-blocking sein. Das bedeutet, dass Modernizr heruntergeladen und in JavaScript ausgeführt werden muss, bevor eine Webseite überhaupt Inhalte auf dem Bildschirm anzeigen kann – was unsere Seitenladezeit erhöht (besonders auf mobilen Geräten)!
- Um Tests durchzuführen, muss Modernizr oft tatsächlich versteckte HTML-Knoten erstellen und testen, ob es funktioniert. Um beispielsweise die Unterstützung für
<canvas>zu testen, führt Modernizr den folgenden JavaScript-Code aus:return !!(document.createElement('canvas').getContext && document.createElement('canvas').getContext('2d'));. Dies verbraucht CPU-Rechenleistung, die anderswo verwendet werden könnte. - Das von Modernizr verwendete CSS-Nachfahrenselektor-Muster erhöht die CSS-Spezifität. (Siehe Harry Roberts' hervorragender Artikel darüber, warum „Spezifität ein zu vermeidendes Merkmal ist.“)
- Obwohl Modernizr viele Tests abdeckt (über 150), deckt es immer noch nicht das gesamte Spektrum der CSS-Eigenschaften ab, wie es
@supporttut. Das Modernizr-Team pflegt aktiv eine Liste dieser nicht erkannten Features.
Da Feature-Abfragen bereits weit verbreitet im Browser-Umfeld implementiert sind (sie decken zum Zeitpunkt der Erstellung etwa 93,42% der globalen Browser ab), ist es schon eine Weile her, dass ich Modernizr verwendet habe. Es ist jedoch gut zu wissen, dass es als Option existiert, falls wir auf die Grenzen von @supports stoßen oder wenn wir Benutzer unterstützen müssen, die aus verschiedenen Gründen immer noch in älteren Browsern oder Geräten gefangen sind.
Darüber hinaus wird Modernizr normalerweise in Verbindung mit @supports verwendet, wie folgt:
.generatedcontent input {
display: none;
}
label:hover::before {
color: #c6c8c9;
}
input:checked + label::before {
color: black;
}
@supports (transform: scale(2)) and (animation-name: beat) {
input:checked + label::before {
color: #e0e1e2;
animation-name: beat;
animation-iteration-count: infinite;
animation-direction: alternate;
}
}
Dies löst Folgendes aus:
- Wenn
::beforenicht unterstützt wird, greift unser CSS auf die Standard-HTML-Radioauswahl zurück. - Wenn weder
transform(scale(2))nochanimation-name: beatunterstützt werden, aber::beforeunterstützt wird, ändert sich das Herz-Icon beim Auswählen zu Schwarz anstatt zu animieren. - Wenn
transform(scale(2),animation-name: beatund::beforeunterstützt werden, animiert sich das Herz-Icon beim Auswählen.
Die Zukunft der CSS-Feature-Erkennung
Bis zu diesem Punkt habe ich es vermieden, über Feature-Erkennung in einer Welt, die von JavaScript gefressen wird, oder vielleicht sogar einer Post-JavaScript-Welt zu sprechen. Vielleicht sogar absichtlich, da aktuelle Iterationen an der Schnittstelle zwischen CSS und JavaScript extrem umstritten und spaltend sind.
Von diesem Moment an war die Web-Community in zwei Lager gespalten, die von einer intensiven Debatte zwischen denen, die CSS als eine unantastbare Schicht im Paradigma der „Trennung der Zuständigkeiten“ (Inhalt + Präsentation + Verhalten, HTML + CSS + JS) betrachten, und denen, die diese goldene Regel einfach ignoriert und andere Wege gefunden haben, die Benutzeroberfläche zu gestalten, typischerweise durch Anwenden von CSS-Stilen über JavaScript. Diese Debatte wird von Tag zu Tag intensiver und führt zu einer Spaltung in einer Community, die früher gegen diese Art von „Religionskriegen“ immun war.
—Cristiano Rastelli, Lass Frieden auf CSS sein (2017)
Ich denke jedoch, dass es von Wert sein könnte, zu untersuchen, wie Feature-Erkennung in der modernen CSS-in-JS-Toolchain angewendet wird, wie folgt:
- Es bietet eine Gelegenheit, zu untersuchen, wie CSS-Feature-Erkennung in einer radikal anderen Umgebung funktionieren würde.
- Es zeigt Feature-Erkennung als Technik, im Gegensatz zu einer spezifischen Technologie oder einem Tool.

Mit diesem im Hinterkopf wollen wir zunächst eine Implementierung unseres Popups mit der am weitesten verbreiteten CSS-in-JS-Bibliothek (zumindest zum Zeitpunkt der Erstellung) Styled Components untersuchen.
So wird es im Internet Explorer 8 aussehen
In unseren bisherigen Beispielen konnten wir CSS-Regeln bedingt ausführen, basierend auf der Browserunterstützung von ::before (via Modernizr) und transform (via @supports). Durch die Nutzung von JavaScript können wir dies jedoch noch weiter treiben. Da sowohl @supports als auch Modernizr ihre APIs über JavaScript bereitstellen, können wir ganze Teile unseres Popups bedingt laden, basierend ausschließlich auf der Browserunterstützung.
Bedenken Sie, dass Sie wahrscheinlich viel Aufwand betreiben müssen, um React und Styled Components in einem Browser zum Laufen zu bringen, der nicht einmal ::before unterstützt (die Überprüfung auf display: grid könnte in diesem Zusammenhang sinnvoller sein), aber um bei den obigen Beispielen zu bleiben, nehmen wir an, dass wir React und Styled Components im Internet Explorer 8 oder niedriger ausführen.
Im obigen Beispiel werden Sie bemerken, dass wir eine Komponente namens ValueSelection erstellt haben. Diese Komponente gibt einen klickbaren Button zurück, der bei jedem Klick die Anzahl der Likes erhöht. Wenn Sie das Beispiel in einem etwas älteren Browser ansehen, werden Sie feststellen, dass anstelle des Buttons ein Dropdown mit Werten von 0 bis 9 angezeigt wird.
Um dies zu erreichen, geben wir bedingt eine erweiterte Version der Komponente zurück, nur wenn die folgenden Bedingungen erfüllt sind:
if (
CSS.supports('transform: scale(2)') &&
CSS.supports('animation-name: beat') &&
Modernizr.generatedcontent
) {
return (
<React.Fragment>
<Modern type="button" onClick={add}>{string}</Modern>
<input type="hidden" name="liked" value={value} />
</React.Fragment>
)
}
return (
<Base value={value} onChange={select}>
{
[1,2,3,4,5,6,7,8,9].map(val => (
<option value={val} key={val}>{val}</option>
))
}
</Base>
);
Interessant an diesem Ansatz ist, dass die Komponente ValueSelection nur zwei Parameter bereitstellt:
- Die aktuelle Anzahl der Likes
- Die Funktion, die ausgeführt wird, wenn die Anzahl der Likes aktualisiert wird
<Overlay>
<Popup>
<Title>How much do you like popups?</Title>
<form>
<ValueInterface value={liked} change={changeLike} />
<Button type="submit">Submit</Button>
</form>
</Popup>
</Overlay>
Mit anderen Worten, die Logik der Komponente ist vollständig von ihrer Darstellung getrennt. Die Komponente selbst entscheidet intern, welche Darstellung angesichts der Support-Matrix eines Browsers am besten funktioniert. Die bedingte Darstellung, die innerhalb der Komponente selbst abstrahiert ist, eröffnet aufregende neue Wege beim Erstellen browserübergreifend kompatibler Schnittstellen, wenn man in einem Frontend- und/oder Designteam arbeitet.
Hier ist das Endergebnis:
…und wie es theoretisch im Internet Explorer 8 aussehen sollte
Additional Resources
Wenn Sie tiefer in das Obige eintauchen möchten, finden Sie hier einige Ressourcen:
- Mozilla Developer Network Artikel zur Feature-Erkennung
- Mozilla Developer Network Artikel zur User-Agent-Erkennung
- Mozilla Developer Network Artikel zu CSS-Feature-Abfragen
- Offizielle Dokumentation zu Feature-Abfragen von der CSSWG
- Modernizr-Dokumentation
Schalk ist ein südafrikanischer Frontend-Entwickler/Designer, der sich leidenschaftlich dafür einsetzt, welche Rolle Technologie und das Web als positive Kraft in seinem Heimatland spielen können. Er arbeitet Vollzeit mit einer Gruppe für Civic Tech aufgeschlossener Entwickler bei einer südafrikanischen Non-Profit-Organisation namens OpenUp.
Er hilft auch bei der Verwaltung eines Kollaborationsraums namens Codebridge, in dem Entwickler ermutigt werden, mit Technologie als Werkzeug zur Überbrückung sozialer Gräben und Lösung von Problemen gemeinsam mit lokalen Gemeinschaften zu experimentieren.
Laut Caniuse unterstützt IE8 Pseudoelemente, aber mit einfacher, nicht doppelter Doppelpunkt-Syntax.
Das stimmt absolut. Lustigerweise haben wir heute dazu gepostet: https://css-tricks.de/to-double-colon-or-not-do-double-colon/
Danke dafür, John! Ich habe es gerade getestet und es ist tatsächlich der Fall! Es scheint, als müsste ich meine Beispiele irgendwann aktualisieren, oder ich muss sie auf Internet Explorer 7 herabstufen. :)
Werde eine Notiz im Artikel hinzufügen.
Interessiert es jemanden, ob es Nachteile hat, einfach durchgängig einen einzelnen Doppelpunkt zu verwenden – abgesehen davon, dass es nicht die korrekte Syntax ist?
Feature-Erkennung für Selektoren ist möglich, indem man die Tatsache nutzt, dass Browser Selektoren ignorieren, die sie nicht verstehen. Dies geschieht automatisch, wenn man einen Selektor normal verwendet. Für den Fall, dass der zu testende Selektor nicht Teil des anzuwendenden Selektors ist, kann man ihn einfach nach einem Komma in einer Form hinzufügen, die nichts abgleicht. In Ihrem Fall könnten Sie also tun:
_::beforewird nichts auf der Seite für Browser beeinflussen, die das Pseudoelement unterstützen, aber IE 8- wird es nicht verstehen und somit die gesamte Regel ignorieren.Das ist erstaunlich! Daran habe ich nicht einmal gedacht. Danke für den Tipp, Toby! :)
Das Setzen einer Eigenschaft von "display: none" auf ein wird es für assistierende Technologien, wie z. B. Screenreader, unbrauchbar machen. Bitte blenden Sie wesentliche Elemente zugänglich aus und erhalten Sie die Bedienbarkeit und Fokussierbarkeit, falls zutreffend.
Die Backticks fehlen.. zwischen 'ein' und 'wird' bitte lesen Sie
<input type="radio" ..>:)Das ist tatsächlich ein sehr guter Punkt, Hans! Ich habe das obige Beispiel nur zu Illustrationszwecken erstellt, aber es wäre vielleicht erwähnenswert, etwas wie das Folgende hinzuzufügen anstelle von
display: none, während wir schon dabei sindposition:absolute;left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;