Elementabfragen und wie Sie sie heute verwenden können
Veröffentlicht: 2022-03-10Denken Sie für einen Moment an eine physische Struktur. Wenn Sie ein großes Gebäude mit schwachem Material bauen, ist viel externe Unterstützung erforderlich, um es zusammenzuhalten, und die Dinge müssen überbaut werden, um stabil zu bleiben. Wenn Sie eine Website aus HTML, CSS und JavaScript erstellen, kann diese externe Unterstützung wie Frameworks, Plugins, Präprozessoren, Transpiler, Bearbeitungswerkzeuge, Paketmanager und Build-Prozesse aussehen.
Anstatt ein weiteres Plugin an die Spitze des Stapels zu setzen, fragte ich mich, ob wir durch die Erweiterung einer der Kernsprachen, CSS , das Material stärken könnten, aus dem Websites aufgebaut sind, und bessere, stärkere Websites entwickeln könnten, die weniger externe Unterstützung und Tools erfordern bauen.
Der aktuelle Status von Elementabfragen
Mit Tools wie CSS-Präprozessoren schreiben wir CSS in Kurzschrift, um es später in seine vollständige Form zu erweitern (bevor es in einem Browser angezeigt wird). Plugins können auf der Seite neben den von ihnen betroffenen Elementen arbeiten, aber um Stile anzuwenden, schreiben sie entweder CSS-Stile direkt in HTML oder schalten Klassennamen um, die andere CSS-Regeln anwenden. In beiden Fällen müssen wir das CSS schreiben oder generieren, das wir benötigen, bevor die Seite tatsächlich geladen wird.
Das Problem
Das Problem bei dieser Methode ist, dass selbst die besten Plugins oft eine Anpassung und Konfiguration in jedem von Ihnen verwendeten Layout erfordern. Auch wenn JavaScript Stile für Sie schreibt, kann es schwierig sein, Ihre Plugin-basierte Logik und Ihre CSS-Stile zusammenzuhalten, wenn Sie Code umgestalten oder wiederverwenden.
Ein weiteres Problem mit Präprozessoren besteht darin, dass alle in Kurzschrift geschriebenen Fehler schnell zu einem viel größeren Durcheinander werden, sobald das CSS in seine vollständige Form erweitert wurde. Bei der Verwendung von Plugins fügen wir viele potenzielle Fehlerquellen hinzu. Wir verwenden möglicherweise mehrere Plugins, um eine Handvoll verschiedener Dinge zu erreichen, die alle unnötig wären, wenn CSS etwas leistungsfähiger wäre. Dies schafft eine zusätzliche Belastung für Entwickler bei der Wartung, für Browser zum Rendern und für Benutzer zum Herunterladen.
Gibt es Hoffnung für die Zukunft der Webentwicklung?
Im Jahr 2013 schrieb Tyson Matanich einen Artikel mit dem Titel „Media Queries Are Not the Answer: Element Query Polyfill“, in dem das Konzept der Elementabfragen einem großen Publikum vorgestellt wurde. Es löste eine Diskussion darüber aus, wie Plugins und Polyfills erstellt werden könnten, um die Mängel von CSS zu umgehen.
Während wir darauf warten, dass CSS-Funktionen vorankommen, wurde seitdem eine Reihe von Plugins veröffentlicht, die es Entwicklern ermöglichen, Elementabfragen auf verschiedene Arten zu verwenden.
Was sind Elementabfragen?
Elementabfragen sind wie Medienabfragen, außer dass ihre Regeln für die Eigenschaften der tatsächlichen Elemente gelten und nicht für die des Darstellungsbereichs des Browsers.
Wie EQCSS entstand
Ende 2013 arbeitete ich am Frontend einer Ruby on Rails-Webanwendung. Die App musste den Benutzern detaillierte Informationen anzeigen, und das Ziel war es, eine reaktionsschnelle Benutzeroberfläche zu erstellen, die auf Telefonen, Tablets und Desktop-Browsern gleichermaßen gut funktioniert. Dies stellte einige Herausforderungen dar, von denen eine darin bestand, dass viele der wichtigen Inhalte, die angezeigt werden sollten, am besten in Tabellen angezeigt werden sollten – ja, eigentliche table
(um Finanztransaktionen, Sportaufzeichnungen usw. anzuzeigen).
Ich habe mithilfe von Medienabfragen reaktionsschnelle Stile erstellt, die das table
für Browser unterschiedlicher Größe korrekt angezeigt haben. Aber sobald eine dieser responsiven Tabellen in einer Vorlage angezeigt wurde, die eine Seitenleiste enthielt, wurden plötzlich alle meine responsiven Breakpoints zu responsiven Breakpoints . Sie haben die 200 Pixel breite Seitenleiste einfach nicht berücksichtigt, was dazu führte, dass sich die Dinge überlappten und kaputt wirkten.
Ein weiteres Hindernis: Die Länge der Benutzernamen variierte zwischen 3 und 20 Zeichen, und ich wünschte mir, ich könnte die Schriftgröße jedes Benutzernamens automatisch an die Anzahl der enthaltenen Zeichen anpassen . Ich musste jeden Benutzernamen in die Seitenleiste einfügen, und es war schwierig, eine Schriftgröße auszuwählen, die klein genug war, um einen 20-stelligen Benutzernamen aufzunehmen, aber groß genug, damit der Betrachter einen 3-stelligen Benutzernamen sehen konnte.
Um Probleme wie diese zu umgehen, musste ich oft ganze Medienabfragen kopieren und große Teile meiner Codebasis duplizieren, einfach weil ich eine intelligentere Methode brauchte, um die responsiven Stile in jedem Layout anzuwenden. Ich verließ mich auf JavaScript als weitere provisorische Lösung und schrieb viele nahezu identische Funktionen, die eine Seite überwachten und Stile an Stellen anwendeten, die CSS nicht erreichen konnte. Nach einer Weile begann die zusätzliche Belastung durch all diesen doppelten Code die Codebasis zu belasten und machte Änderungen schwierig.
Ich wusste, dass es eine bessere Lösung geben musste, und nach einer Weile begann ich zu denken: Ich brauche keine Medienabfragen – was ich brauche, sind Elementabfragen!
Forschung und Entwicklung
Bis 2014 begann ich mit verschiedenen Methoden zu experimentieren, um CSS über die Eigenschaften von Elementen zu informieren, wie sie auf der Seite erscheinen, damit ich bessere Stile anwenden konnte. Ich hatte gehofft, einen Ansatz zu entdecken, der es mir ermöglichen würde, Stile zu schreiben, die die Schönheit von CSS mit der Leistungsfähigkeit von JavaScript kombinieren.
Einige verworfene Ansätze, die ich aufgegeben habe, sind das Hinzufügen von Attributen zu HTML-Tags, um responsive Unterstützung hinzuzufügen, und der Versuch, Wege zu finden, ganze Blöcke von CSS-Code in JavaScript-basierte if
-Anweisungen einzubetten, um eine Art Frankenstein-Monster zu produzieren, das aus JavaScript zusammengeflickt wird und CSS.
Aber anstatt es einfacher zu machen, hatten all meine gescheiterten Ansätze eines gemeinsam: Sie haben mehr Arbeit verursacht! Ich wusste, dass die richtige Lösung die zu erledigende Arbeit vereinfachen und reduzieren würde, also suchte ich weiter. Durch diese Experimente gelangte ich zu einer verfeinerten Vorstellung von der Art der Syntax, die erforderlich wäre, damit Elementabfragen gut funktionieren.
Wie bereits erwähnt, gibt es für eine Website, die aus HTML, CSS und JavaScript erstellt wurde, externe Unterstützung in Form von Frameworks, Plugins, Präprozessoren, Transpilern, Bearbeitungswerkzeugen, Paketmanagern und Build-Prozessen. Anstatt noch ein weiteres Plugin an die Spitze des Stapels zu setzen, fragte ich mich, ob wir durch die Erweiterung einer der Kernsprachen, CSS, das Material stärken könnten, aus dem Websites aufgebaut sind, und bessere, stärkere Websites erstellen könnten, die weniger externe Unterstützung erfordern Werkzeuge zu bauen.
Die Geburt einer Syntax
Ende 2014, ausgestattet mit einer besseren Vorstellung von der benötigten Syntax, kontaktierte ich Maxime Euziere, einen phänomenalen JavaScript-Code-Golfer, und fragte ihn nach seiner Meinung über die Möglichkeit, CSS mithilfe von JavaScript im Browser zur Laufzeit zu erweitern. Er hat mich nicht nur darüber informiert, dass es möglich ist, sondern er hat mir auch angeboten, mir dabei zu helfen! Wir haben die Syntax EQCSS genannt, kurz für „Element Query CSS“. Der Name ist auch eine Anspielung auf das Wort „Exzess“, denn alles, was es tut, geht über das hinaus, was CSS leisten kann.
Die Notwendigkeit
Meine Anforderung an die Syntax war, dass sie so nah wie möglich an CSS sein sollte – so nah, dass Syntax-Highlighter glauben würden, es sei Standard-CSS. Also habe ich die sinnvolle CSS-Syntax für Elementabfragen entworfen – die Art von Syntax, über die die Leute überrascht sind, existiert noch nicht.
Ich wusste, dass, wenn wir die Browserunterstützung für CSS mit JavaScript erweitern wollten, das Plugin so leicht und unkompliziert wie möglich sein musste, um die Arbeit zu erledigen, was die Verwendung von Bibliotheken wie jQuery zum Erstellen des Plugins ausschloss. Ich brauchte eine reine JavaScript-Bibliothek, die den Browsern, die ich heute unterstützen muss, die Funktionen hinzufügen würde, die ich in Zukunft haben möchte.
Derzeit konzentriert sich die Diskussion in der CSS-Community auf benutzerdefinierte @
-Regeln, und die Diskussion über Elementabfragen ist noch vorläufig. Wir sind wahrscheinlich noch Jahre von einer offiziellen CSS-Spezifikation für solche Funktionen entfernt, und selbst nach einer Spezifikation müssen wir noch auf genügend Browserunterstützung warten, bevor wir diese Funktionen in Websites verwenden können.
Es macht keinen Sinn, darauf zu warten, dass diese Funktionen zu CSS hinzugefügt werden, wenn wir diese Funktionalität heute zum Erstellen und Korrigieren von Websites benötigen.
Das Ergebnis
Das Ergebnis dieser Forschung war die Erstellung einer Syntax, die einen neuen Satz erweiterter Reaktionsbedingungen, bereichsbezogene Stile und neue Selektoren für Targeting-Elemente sowie eine reine JavaScript-Bibliothek namens EQCSS.js enthält. Außerdem wurde Unterstützung für Internet Explorer (IE) 8 in einem optionalen externen Polyfill bereitgestellt. Sowohl das Plugin als auch Polyfill wurden unter der MIT-Lizenz veröffentlicht und können von jedem kostenlos verwendet werden.
Anwendungsfälle für Elementabfragen
Plugin-Entwickler
Beim Erstellen von UI-Komponenten und Widgets sind Entwickler oft durch Medienabfragen eingeschränkt. Wir müssen uns oft zwischen dem Erstellen vieler verschiedener Layouts entscheiden, die von der Person, die das Plugin verwendet, konfiguriert werden können, und der Vereinfachung der Benutzeroberfläche bis zu dem Punkt, an dem Sie eine Einheitslösung erstellen können.
Aber wenn wir Plugins und Schnittstellen mit Elementabfragen entwerfen, können wir leicht ansprechende Stile schreiben, die alle Situationen abdecken, die wir erwarten, und sie wirklich kugelsicher machen, unabhängig davon, welche Inhalte der Benutzer einfügt oder wo das Plugin auftaucht. Angenommen, wir könnten ein Widget mit Layouts gestalten, die zwischen 150 und 2000 Pixel breit sind. Egal, wo dieses Widget auf einer Website angezeigt wird, es würde immer großartig aussehen.
Vorlagenersteller
Beim Prototyping einer Website ist es üblich, Designelemente auf der Seite neu zu organisieren und das Design als eine Sammlung modularer Komponenten zu betrachten. Wenn Sie CSS-Medienabfragen geschrieben haben, kann dies manchmal ein Fall von verfrühter Optimierung sein . Durch das Entwerfen mit Elementabfragen bleiben Sie reaktionsschnelle Bedingungen vom Layout unabhängig, was Ihnen viel mehr Flexibilität gibt, Dinge zu verschieben, ohne Stile so sehr überarbeiten zu müssen.
Zu den Dingen, die ich als besonders nützlich empfunden habe, gehören:
- Navigationsleisten,
- Modale,
- Anmelde- und Anmeldeformulare,
- Fußzeilen,
- Preisdiagramme,
- Startseiten,
- Tische,
- Registerkarten,
- Akkordeons,
- Seitenleisten-Widgets,
- Mediaplayer,
- Erfahrungsberichte.
Jedes Designelement kann überall „angepaßt“ und portiert werden – von Seite zu Seite oder von Website zu Website.
Geräteunterstützung
Eines der Probleme, mit denen Sie bei der Unterstützung des Webs auf Mobilgeräten konfrontiert sind, ist die Fülle an Hardware. Der Markt für Geräte ist fragmentierter denn je und täglich kommen neue Geräte hinzu. Wir können keine Liste der von uns unterstützten Browser und Geräte mehr führen, daher ist es wichtig zu wissen, dass ein Design überall funktioniert, sogar auf Geräten, die noch nicht veröffentlicht wurden.
Durch die Verwendung von Elementabfragen können Sie Websites besser gestalten und einige dieser browserübergreifenden Unterschiede beseitigen.
Viele Artikel, die kürzlich über die Notwendigkeit von Elementabfragen geschrieben wurden, veranschaulichen viele der Anwendungsfälle im Detail. Machen wir also weiter, wie man sie benutzt!
So schreiben Sie Elementabfragen
Der Einstieg in EQCSS ist einfach. Alles, was Sie brauchen, um mit der Verwendung der EQCSS-Syntax zu beginnen, ist, das JavaScript irgendwo in Ihren HTML-Code einzufügen.
Herunterladen von EQCSS.js
Wenn Sie das EQCSS-Projekt von GitHub klonen möchten, können Sie Folgendes eingeben:
git clone https://github.com/eqcss/eqcss.git
Wenn Sie npm verwenden, können Sie EQCSS mit dem folgenden Befehl zu Ihrem Projekt hinzufügen:
npm install eqcss
Hinzufügen von EQCSS.js zu Ihrem HTML
Nachdem Sie EQCSS heruntergeladen haben, können Sie es mit einem script
-Tag zu Ihrem HTML-Code hinzufügen:
<script src="EQCSS.js"></script>
Diese Datei ( EQCSS.js
) enthält Unterstützung für alle aktuellen Browser, einschließlich IE 9 und höher. Um IE 8 zu unterstützen, hätten wir viele andere Polyfills verwenden müssen. Denken Sie daran, dass IE 8 nicht einmal CSS-Medienabfragen ohne Polyfill unterstützt, daher ist es ziemlich erstaunlich, dass wir Elementabfragen auch dort zum Laufen bringen konnten. Um IE 8-Unterstützung für eine Website mit EQCSS einzubinden, fügen Sie den folgenden Link vor Ihrem Link zum Haupt-Plugin hinzu:
<!‐‐[if lt IE 9]><script src="EQCSS‐polyfills.js"></script><![endif]‐‐>
EQCSS ausführen
Standardmäßig berechnet das EQCSS-Plugin alle Stile, die es findet, sobald die Seite geladen wird, und auch immer dann, wenn es erkennt, dass die Größe des Browsers geändert wird, ähnlich wie bei Medienabfragen. Sie können EQCSS.apply()
auch manuell mit JavaScript aufrufen, um Stile jederzeit neu zu berechnen, was nützlich sein kann, nachdem der Inhalt auf der Seite aktualisiert wurde.
CSS für Elementabfragen schreiben
Das Plug-in EQCSS.js kann Stile auf verschiedene Arten lesen. Sie können EQCSS in alle style
-Tags auf einer HTML-Seite einfügen. Sie können EQCSS auch in einem externen CSS-Stylesheet schreiben.
Wenn Sie Ihren EQCSS-basierten Code von Ihrem CSS getrennt halten möchten, können Sie die EQCSS-Syntax mithilfe des script
-Tags laden, wobei der Typ auf text/eqcss
. Sie können Stile in einem Tag wie diesem inline hinzufügen oder mit <script type=“text/eqcss” src=styles.eqcss></script>
auf ein externes .eqcss
-Stylesheet verlinken, wodurch eine Datei namens styles.eqcss
.
Anatomie einer Elementabfrage
Style-Scoping
Die Syntax in EQCSS zum Schreiben von Elementabfragen ist der Formatierung von CSS-Medienabfragen sehr ähnlich, aber anstelle von @media
beginnen wir die Abfrage mit @element
. Die einzige andere Information, die wir bereitstellen müssen, ist mindestens ein Selektor, für den diese Stile gelten sollen. So erstellen Sie einen neuen Geltungsbereich für ein Element mit dem Namen <div class=“widget”>
:
@element '.widget' { }
Das Element zwischen den Anführungszeichen (in diesem Fall .widget
) kann ein beliebiger gültiger CSS-Selektor sein. Mit dieser Abfrage haben wir einen neuen Gültigkeitsbereich für das .widget
Element erstellt. Wir haben noch keine Responsive-Bedingungen für den Geltungsbereich aufgenommen, daher würden alle Stile in einer Abfrage wie dieser jederzeit auf das bereichsbezogene Element angewendet werden.
Ohne die Möglichkeit, Stile auf ein oder mehrere Elemente (statt auf die gesamte Seite auf einmal) zu beschränken, könnten wir reaktionsschnelle Abfragen nicht nur auf diese Elemente anwenden. Sobald wir diesen Bereich auf Elementebene erstellt haben, wird die Verwendung der fortgeschritteneren Funktionen der EQCSS-Syntax einfach – wie beispielsweise der $parent
-Metaselektor – da JavaScript jetzt einen Referenzpunkt hat, von dem aus Dinge wie der parentNode
des Bereichs berechnet werden können Element. Das ist riesig!
Richtig, CSS enthält bereits einen direkt nachkommenden Selektor mit dem >
, der es uns ermöglicht, Elemente auszuwählen, die direkte Kinder des angegebenen Elements sind. Aber CSS bietet derzeit keine Möglichkeit, in die andere Richtung im Stammbaum zu reisen, um ein Element auszuwählen, das ein anderes Element enthält, das man als Elternelement bezeichnen würde. Die „CSS Selectors Level 4“-Spezifikation enthält jetzt einen :has()
-Selektor, der ähnlich wie der :has()
-Selektor von jQuery funktioniert, aber derzeit keine Browserunterstützung bietet. Scoped CSS ermöglicht eine andere Art von übergeordnetem Selektor.
Nachdem wir nun einen Bereich im Kontext des .widget
Elements geöffnet haben, können wir Stile aus seiner Perspektive schreiben, um auf sein eigenes übergeordnetes Element abzuzielen:
@element '.widget' { $parent { /* These styles apply to the parent of .widget */ } }
Ein weiteres Beispiel für spezielle Selektoren, die in jeder Elementabfrage verwendet werden können, sind die Selektoren $prev
und $next
, die die vorherigen und nächsten gleichgeordneten Elemente darstellen. Obwohl CSS das nächste Geschwister unseres Widgets mit einem Selektor wie .widget + *
erreichen kann, gibt es in CSS keine Möglichkeit, rückwärts zu gelangen und das Element auszuwählen, das direkt vor einem anderen Element steht.
<section> <div>This will be the previous item</div> <div class="widget">This is the scoped element</div> <div>This will be the next item</div> </section> <style> @element '.widget' { $prev { /* These styles apply to the element before .widget */ } $next { /* These styles apply to the element after .widget */ } } </style>
Elementabfragen
Entwickler verwenden am häufigsten CSS-Medienabfragen für responsives Design, indem sie Stile basierend auf der Höhe oder Breite des Darstellungsbereichs des Browsers anwenden. Die EQCSS-Syntax unterstützt viele neue Arten von Reaktionsbedingungen. Anstatt nur mit der Breite und Höhe des Browsers zu arbeiten, können Sie Stile schreiben, die auf Elemente basierend auf ihren eigenen Eigenschaften angewendet werden, z. B. wie viele untergeordnete Elemente es enthält oder wie viele Zeichen oder Textzeilen sich im Moment im Element befinden .
Das Hinzufügen dieser Responsive-Bedingungen zu Ihren bereichsbezogenen Stilen ähnelt dem Formatieren von Medienabfragen: Sie würden and (condition: value)
für jede Bedingung hinzufügen, die Sie überprüfen möchten. In diesem Beispiel prüfen wir, ob .widget
Elemente auf der Seite mindestens 500 Pixel breit angezeigt werden.
@element '.widget' and (min‐width: 500px) { /* CSS rules here */ }
Die Syntax einer Elementabfrage gliedert sich wie folgt:
- element query
@element selector_list [ condition_list ] { css_code }
- Auswahlliste
" css selector [ "," css selector ]* "
- Bedingungsliste
and ( query_condition : value ) [ "and (" query condition ":" value ")" ]*
- Wert
number [ css unit ]
- Abfragebedingung
min-height | max-height | min-width | max-width | min-characters | max-characters | min-lines | max-lines | min-children | max-children | min-scroll-y | max-scroll-y | min-scroll-x | max-scroll-x
min-height | max-height | min-width | max-width | min-characters | max-characters | min-lines | max-lines | min-children | max-children | min-scroll-y | max-scroll-y | min-scroll-x | max-scroll-x
- CSS-Einheit
% | px | pt | em | cm | mm | rem | ex | ch | pc | vw | vh | vmin | vmax
% | px | pt | em | cm | mm | rem | ex | ch | pc | vw | vh | vmin | vmax
Als weiteres Beispiel sehen Sie hier, wie Sie eine Abfrage schreiben, die das body
-Element rot färbt, wenn das .widget
Element eine Breite von 500 Pixeln erreicht:
@element '.widget' and (min‐width: 500px) { body { background: red; } }
Beachten Sie, dass sich das body
-Element ändert, wenn das .widget
eine bestimmte Breite erreicht, nicht das .widget
Element selbst!
Bedingungen für Elementabfragen
Nachfolgend finden Sie die vollständige Liste der reaktionsfähigen Bedingungen, die EQCSS unterstützt.
Breitenbasierte Bedingungen
-
min-width
Demo für Pixel, Demo für Prozentsätze -
max-width
Demo für Pixel, Demo für Prozentsätze
Höhenbasierte Bedingungen
-
min-height
Demo für Pixel, Demo für Prozentsätze -
max-height
Demo für Pixel, Demo für Prozentsätze
Zählbasierte Bedingungen
-
min-characters
Demo für Blockelemente, Demo für Formulareingaben -
max-characters
Demo für Blockelemente, Demo für Formulareingaben -
min-lines
Demo -
max-lines
Demo -
min-children
Demo -
max-children
Demo
Scroll-basierte Bedingungen
-
min-scroll-y
Demo -
max-scroll-y
Demo -
min-scroll-x
Demo -
max-scroll-x
Demo
Sie können eine beliebige Anzahl dieser Bedingungen in Ihren Elementabfragen für wirklich multidimensionale responsive Stile kombinieren. Dies gibt Ihnen viel mehr Flexibilität und Kontrolle darüber, wie Elemente gerendert werden. Um beispielsweise die Schriftgröße einer Kopfzeile mit mehr als 15 Zeichen zu verkleinern, wenn weniger als 600 Pixel Platz für die Anzeige verfügbar sind, könnten Sie die Bedingungen für max‐characters: 15
und max‐width: 600px
:
h1 { font‐size: 24pt; } @element 'h1' and (min‐characters: 16) and (max‐width: 600px) { h1 { font‐size: 20pt; } }
Meta-Selektoren
Eines der Probleme, auf die Sie stoßen könnten, wenn Sie beginnen, bereichsbezogene Stile mit responsiven Bedingungen zu schreiben, besteht darin, dass, wenn sich mehrere Instanzen desselben Selektors auf einer Seite befinden, die Verwendung dieses Selektors in Ihrer Elementabfrage Stile auf alle Instanzen dieses Selektors auf der Seite anwendet Seite, wenn einer von ihnen die Bedingungen erfüllt. Angenommen, wir hätten zwei .widget
auf der Seite (vielleicht eines in der Seitenleiste und ein anderes in voller Breite) und wir haben unsere Elementabfrage wie folgt geschrieben:
@element '.widget' and (min‐width: 500px) { .widget h2 { font‐size: 14pt; } }
Dies würde bedeuten, dass, wenn .widget
Elemente auf der Seite mindestens 500 Pixel breit ist, der Stil für beide .widget
Elemente gelten würde. Dies ist wahrscheinlich nicht das, was wir in den meisten Fällen wollen. Hier kommen Meta-Selektoren ins Spiel!
Die zwei Teile, aus denen unsere Elementabfrage besteht, sind der Selektor und die Antwortbedingung. Wenn wir also nur auf die Elemente auf der Seite abzielen möchten, die gleichzeitig sowohl dem Selektor als auch den Responsive-Bedingungen entsprechen, können wir den Meta-Selektor $this
verwenden. Wir können unser letztes Beispiel so umschreiben, dass der Stil nur für .widget
-Elemente gilt, die der Bedingung min‐width: 500px
entsprechen:
@element '.widget' and (min‐width: 500px) { $this h2 { font‐size: 14pt; } }
Eine Reihe neuer Selektoren werden von der EQCSS-Syntax unterstützt, die in regulärem CSS nicht enthalten sind. Hier ist die vollständige Liste:
-
$this
Demo -
$parent
Demo -
$root
Demo -
$prev
Demo -
$next
Demo
Diese Selektoren funktionieren nur in einer Elementabfrage.
Öffnen des Portals zwischen JavaScript und CSS
-
eval(')
demo
Das letzte und letzte Feature von EQCSS ist das wildeste von allen: eval(')
. Durch diese Tür liegt die gesamte Leistungsfähigkeit von JavaScript, die über CSS zugänglich ist. Obwohl JavaScript Stile auf Elemente anwenden kann, hat es derzeit Schwierigkeiten, einige Dinge zu erreichen, wie z. B. die :before
und :after
-Pseudoelemente. Aber was wäre, wenn CSS JavaScript aus der anderen Richtung erreichen könnte? Anstatt CSS-Eigenschaften durch JavaScript festzulegen, was wäre, wenn CSS JavaScript erkennen könnte?
Hier kommt eval(')
ins Spiel. Sie können auf jedes JavaScript zugreifen und es auswerten, ob Sie den Wert einer JavaScript-Variablen in Ihrem CSS verwenden, um einen JavaScript-Einzeiler auszuführen (wie eval('new Date().getFullYear()')
), um Werte über den Browser und andere Elemente zu ermitteln, die JavaScript messen kann (wie eval('innerHeight')
) oder um eine JavaScript-Funktion auszuführen und den zurückgegebenen Wert in Ihren CSS-Stilen zu verwenden. Hier ist ein Beispiel, das 2016
in einem <footer>
-Element ausgibt:
@element 'footer' { $this:after { content: " eval('new Date().getFullYear()')"; } }
Verwendung von $it innerhalb von eval(')
Beim Auswerten von JavaScript funktioniert eval(')
auch im Kontext des Elements mit aktivem Gültigkeitsbereich, dem gleichen Element, auf das Stile für $this
angewendet werden. Sie können $it
in JavaScript, das in eval(')
geschrieben ist, als Platzhalter für das Bereichselement verwenden, wenn es Ihnen hilft, den Code zu strukturieren, aber wenn es weggelassen wird, funktioniert es auf die gleiche Weise. Nehmen wir zum Beispiel an, wir haben ein div
mit dem Wort „hello“ darin. Der folgende Code würde „hello hallo“ ausgeben:
<div>hello</div> <style> @element 'div' { div:before { content: "eval('$it.textContent') "; } } </style>
Hier bezieht sich $it
auf das div
, da es sich um den derzeit gültigen Selektor handelt. Sie können das $it
auch weglassen und den folgenden Code schreiben, um dasselbe anzuzeigen:
@element 'div' { div:before { content: "eval('textContent') "; } }
eval(')
kann in Situationen hilfreich sein, in denen CSS keine Messungen oder Ereignisse kennt, die auf der Seite nach dem Laden auftreten. Zum Beispiel haben Iframe-Elemente, die zum Einbetten von YouTube-Videos verwendet werden, eine bestimmte Breite und Höhe. Während Sie die Breite in CSS auf „ auto
“ setzen können, gibt es keine einfache Möglichkeit, das korrekte Seitenverhältnis von Breite zu Höhe beizubehalten, wenn das Video erweitert wird, um den verfügbaren Platz auszufüllen.
Eine gängige Problemumgehung zum Beibehalten reaktionsfähiger Seitenverhältnisse beim Skalieren besteht darin, den Inhalt, der sein Seitenverhältnis beibehalten muss, in einem Wrapper zu platzieren und dann dem Wrapper eine Auffüllung mit einem Wert hinzuzufügen, der auf dem Verhältnis von Breite zu Höhe basiert, das Sie beibehalten möchten. Dies funktioniert, erfordert jedoch, dass Sie das Seitenverhältnis aller Videos im Voraus kennen, und erfordert mehr HTML-Markup (ein Wrapper-Element) für jedes Video, das Sie responsiv einbetten möchten. Multiplizieren Sie das auf jeder Website, die responsive Videos hat, und das ist eine Menge Kram, der nicht da sein müsste, wenn CSS nur ein bisschen intelligenter wäre.
Vielleicht besteht ein besserer Ansatz für reaktionsschnelle Seitenverhältnisse darin, jedes Video ohne Polsterung in einen Wrapper zu platzieren und dann eine JavaScript-Bibliothek zu schreiben, die das Seitenverhältnis jedes gefundenen Videos berechnet und die richtige Menge an Polsterung auf jeden Wrapper anwendet.
Aber was wäre, wenn CSS direkt auf diese Messungen zugreifen könnte ? Wir könnten nicht nur das CSS für alle unterschiedlichen Seitenverhältnisse in einer Regel konsolidieren, sondern wenn wir es nach dem Laden der Seite auswerten könnten, könnten wir eine Regel schreiben, die jedes Video, das wir ihm jemals geben, in der Zukunft reaktionsschnell in der Größe ändert. Und wir könnten das alles ohne Wrapper machen!
Wenn Ihnen das zu gut erscheint, um wahr zu sein, schauen Sie sich das an. So einfach ist es, Wrapper-freie Iframe-Elemente mit reaktionsschneller Größenänderung in EQCSS zu schreiben:
@element 'iframe' { $this { margin: 0 auto; width: 100%; height: eval('clientWidth/(width/height)'); } }
width
und height
beziehen sich hier auf die Attribute width=“”
und height=“”
im Iframe in HTML. JavaScript kann die Berechnung von (width/height)
durchführen, was uns das Seitenverhältnis liefert; und um es auf eine beliebige Breite anzuwenden, würden wir einfach die aktuelle Breite des iframe-Elements durch das Verhältnis teilen.
Dies hat die Prägnanz und Lesbarkeit von CSS und die gesamte Leistungsfähigkeit von JavaScript. Keine zusätzlichen Wrapper erforderlich, keine zusätzlichen Klassen und kein zusätzliches CSS.
Seien Sie jedoch vorsichtig mit eval(')
. Es gibt einen Grund, warum CSS-Ausdrücke in der Vergangenheit als gefährlich galten, und es gibt auch einen Grund, warum wir die Idee ausprobiert haben. Wenn Sie nicht darauf achten, auf wie viele Elemente Sie sie auf der Seite anwenden oder wie oft Sie Stile neu berechnen, kann JavaScript dazu führen, dass Dinge hundertmal häufiger als nötig ausgeführt werden. Glücklicherweise erlaubt uns EQCSS, EQCSS.apply()
oder EQCSS.throttle()
aufzurufen, um die Stile manuell neu zu berechnen, sodass wir mehr Kontrolle darüber haben, wann Stile aktualisiert werden.
Die Gefahrenzone!
Andere Probleme können auftreten, wenn Sie Abfragen mit widersprüchlichen Bedingungen oder Stilen erstellen. EQCSS wird wie CSS von oben nach unten gelesen, wobei eine Hierarchie der Spezifität verwendet wird. Obwohl CSS eine deklarative Sprache ist, enthält sie einige erweiterte Funktionen. Es ist nur ein paar Schritte davon entfernt, Turing-vollständig als Programmiersprache zu sein. Bisher war das Debuggen von CSS eine ziemlich unkomplizierte Angelegenheit, aber EQCSS verwandelt CSS von einer einfach interpretierten deklarativen Sprache in eine dynamische Stylesheet-Sprache mit einer zusätzlichen Interpretationsebene zwischen CSS und dem Browser. Mit diesem Neuland geht eine Vielzahl potenzieller neuer Fallstricke einher.
Hier ist ein Beispiel für eine reziproke Schleife in EQCSS, etwas, gegen das normale CSS-Medienabfragen per Design immun sind:
@element '.widget' and (min‐width: 300px) { $this { width: 200px; } }
Ich nenne das jekyll: hide;
CSS. Aber zusätzlich zu einem Stil, der sich ständig selbst auslöst, gibt es auch die Möglichkeit, mehrere Abfragen zu schreiben, die sich gegenseitig auslösen, was wir eine „doppelt invertierte reziproke Schleife“ nennen, die schlimmste von allen:
@element '.widget' and (min‐width: 400px) { $this { width: 200px; } } @element '.widget' and (max‐width: 300px) { $this { width: 500px; } }
Theoretisch würde dieses unglückliche Widget in einer Schleife stecken bleiben, die Größe zwischen 200 und 500 Pixel bis zum Ende der Zeit ändern und sich nicht auf eine Breite festlegen können. Für solche Fälle berechnet EQCSS einfach die Regeln in der Reihenfolge, in der sie ausgewertet werden, prämiert den Gewinner und fährt fort. Wenn Sie die Reihenfolge ändern, in der diese Regeln erscheinen, würde der letztere Stil immer gewinnen, wenn sie von gleicher Spezifität sind.
Einige Leute sagen, dass die Fähigkeit, Schleifen (oder sogar doppelt invertierte reziproke Schleifen) zu erstellen, ein Designfehler ist, aber um zu verhindern, dass Schleifen möglich sind, müssten Sie die Leistung von EQCSS so begrenzen, dass die meisten davon entfernt würden der Wert, den die Syntax bereitstellt. Andererseits ist das Erstellen von Endlosschleifen in JavaScript sehr einfach, aber das wird nicht als Fehler der Sprache angesehen – es wird als Beweis für ihre Leistungsfähigkeit angesehen! Dasselbe gilt für Elementabfragen.
Debuggen von Elementabfragen
Derzeit kann sich das Debuggen von Elementabfragen ein bisschen wie das Debuggen von Medienabfragen anfühlen, bevor wir Tools wie den Webinspektor hatten, um uns die Stile so anzuzeigen, wie sie auf der Seite berechnet wurden. Im Moment erfordert das Debuggen und Entwickeln von Elementabfragen, dass der Entwickler ein mentales Modell darüber pflegt, welches reaktionsfähige Verhalten auftreten soll. In Zukunft könnte es möglich sein, EQCSS-fähige Entwicklertools zu erstellen, aber derzeit kennen die Entwicklertools in allen gängigen Browsern nur die Stile, die EQCSS bereits auf die Elemente auf der Seite angewendet hat, und sie kennen sie nicht die Reaktionsbedingungen, die EQCSS beobachtet.
So entwerfen Sie mit Elementabfragen
Die einfachste Möglichkeit, Elementabfragen zu nutzen, besteht darin, vorhandene Designs mithilfe von Medienabfragen in Elementabfragen umzuwandeln, Elemente und ihre responsiven Stile aus einem Layout zu „befreien“ und es einfach zu machen, diesen Code in anderen Seiten und Projekten wiederzuverwenden. Die folgende Medienabfrage und Elementabfrage könnten dasselbe bedeuten:
footer a { display: inline-block; } @media (max‐width: 500px) { footer a { display: block; } }
footer a { display: inline-block; } @element 'footer' and (max‐width: 500px) { $this a { display: block; } }
Der Unterschied besteht darin, dass im ursprünglichen Beispiel die Fußzeilen-Links als display: block
bleiben, bis der Browser mindestens 500 Pixel breit ist. Das zweite Beispiel mit Elementabfragen würde genauso aussehen, aber nur, wenn das footer
die volle Breite hätte.
Nachdem wir diesen Stil von seiner ursprünglichen Medienabfrage befreit haben, können wir die Fußzeile jetzt in einem Container beliebiger Breite platzieren und sicher sein, dass, wenn die Fußzeile den responsiven Stil anwenden muss (dh wenn sie schmaler als 500 Pixel ist), dies der Fall ist angewandt.
- Stellen Sie sicher, dass
EQCSS.js
im HTML des Zieldokuments vorhanden ist. - Ersetzen Sie im CSS
@media
durch@element
. - Fügen Sie dem Geltungsbereich jeder
@element
Abfrage einen CSS-Selektor hinzu. - Optional: Ersetzen Sie Vorkommen des Bereichselements in Elementabfragen durch
$this
.
Sofern die Designkomponente, die Sie konvertieren, nicht ursprünglich dafür ausgelegt war, die volle Breite des Ansichtsfensters des Browsers zu verwenden, müssen Sie wahrscheinlich die Haltepunkte nach der Konvertierung in Elementabfragen anpassen.
Lock-in vermeiden
Die Erfahrung beim Erstellen von EQCSS-Stilen ähnelt der Erfahrung beim Schreiben von regulärem CSS: Alle Ihre bevorzugten CSS-Eigenschaften und -Techniken sind immer noch vorhanden, nur mit einigen zusätzlichen Funktionen, die ihnen helfen, auf neue Weise zusammenzuarbeiten. Da EQCSS Standard-CSS an den Browser ausgibt, funktioniert jede CSS-Funktion, für die Ihr Browser integrierte Unterstützung bietet, bei Verwendung mit EQCSS. Wenn eines Tages Funktionen wie Elementabfragen und bereichsbezogene Stile in CSS angegeben und in Browsern unterstützt werden, könnten Sie sofort damit beginnen, sie in Ihrem EQCSS-Code zu verwenden, während Sie sich für die anderen Funktionen, die der Browser nicht bietet, immer noch auf EQCSS verlassen dennoch nativ unterstützen.
Da Sie die EQCSS-Syntax sowohl direkt in CSS als auch in einem eigenen Skript mit dem Typ text/eqcss
verwenden können, könnten Sie EQCSS immer noch als Skript laden und Konflikte vermeiden, falls CSS jemals eine Syntax für native Elementabfragen entwickelt .
Mit Blick auf die Zukunft ist eine Lösung, mit der Browserentwickler derzeit experimentieren, Houdini, die Plug-in-Entwicklern den Zugang eröffnen würde, um CSS auf neue Weise zu erweitern, wie z. B. das Hinzufügen von Unterstützung für den Browser selbst. Eines Tages könnte es möglich sein, effizientere Plugins zu schreiben, die die EQCSS-Syntax interpretieren und diese Funktionen direkter und leistungsfähiger in Browser bringen, als es die aktuelle JavaScript-Bibliothek zulässt.
Sollten wir also immer noch Medienabfragen verwenden?
Ja, obwohl Elementabfragen viele neue und aufregende Möglichkeiten bieten, Elemente mit Stilen anzusprechen, werden Medienabfragen (wenn auch begrenzt) im Browser immer schneller ausgeführt als ein Stil, der zur Berechnung auf JavaScript angewiesen ist. CSS-Medienabfragen dienen jedoch mehr als nur dem Stylen von HTML für Bildschirme. CSS-Medienabfragen unterstützen auch druckbasierte Abfragen und andere Möglichkeiten, wie Websites Informationen anzeigen. EQCSS kann in Verbindung mit Medienabfragen für Dinge wie Druckstile verwendet werden, sodass Sie die Medienabfrage nicht zurückziehen müssen, nur weil jetzt auch Elementabfragen verwendet werden können!
Entwerfen mit 20 ⁄ 20 Weitblick
Das Beste, was wir für die Zukunft von CSS tun können, ist, heute so viel wie möglich mit diesen Ideen zu experimentieren. Brainstorming und Theoriebildung über diese Funktionen ist nicht so nützlich wie der Versuch, sie zu implementieren und zu nutzen und die Techniken zu entdecken, die sie nützlich und leistungsfähig machen.
Neben der Bereitstellung einer Lösung für Elementabfragen dient EQCSS.js hoffentlich auch als Plattform für andere Experimente zur Erweiterung von CSS. If you have an idea for a new responsive condition, a new CSS property or a new selector to use in your code, forking EQCSS.js and modifying it to include your idea can get you most of the way there with little effort.
Modular Design
In designing layouts using element queries, the biggest shift is learning how to stop viewing the DOM from the top down and from the perspective of only the root HTML element, and to start thinking about individual elements on the page from their own perspectives within the document.
The old paradigms of “desktop-first” and “mobile-first” responsive design aren't relevant any longer — the new way of building layouts approaches design “element-first.” Using element queries enables you to work on the individual parts that make up a layout, in isolation from one another, styling them to a greater level of detail. If you are using a modular approach for your back-end code already but have so far been unable to package your CSS with your modules because of the difficulties of styling with media queries alone, then element queries will finally allow you to modularize your styles in the same way.
Thinking Element-First
Element-first design is in the same spirit as the atomic design principle but looks different in practice from how most people have implemented atomic design in the past.
For example, let's say you have some HTML like the following, and the desired responsive behavior can be explained as, “The search input and button are displayed side by side until the form gets too narrow. Then, both the input and the button should be stacked on top of each other and displayed full width.”
<form> <input type=search> <input type=button value=Search> </form>
Desktop-First Approach
In a desktop-first mindset, you would write styles for the desktop layout first and then add responsive support for smaller screens.
input { width: 50%; float: left; } @media (max‐width: 600px) { input { width: 100%; float: none; } }
Mobile-First Approach
In a mobile-first mindset, you would design the mobile view first and add support for the side-by-side view only when the screen is wide enough.
input { width: 100%; } @media (min‐width: 600px) { input { width: 50%; float: left; } }
Element-First Approach
In the first two examples, the media breakpoint was set to 600 pixels, and not because that's how wide the inputs will be when they switch. Chances are, the search input is probably inside at least one parent element that would have margins or padding. So, when the browser is 600 pixels wide, those inputs might be somewhere around 550 or 525 pixels wide on the page. In a desktop-first or mobile-first approach, you're always setting breakpoints based on the layout and how elements show up within it. With an element-first layout, you're saying, “I don't care how wide the browser is. I know that the sweet spot for where I want the inputs to stack is somewhere around 530 pixels wide.” Instead of using a media query to swap that CSS based on the browser's dimensions, with element-first design, we would scope our responsive style to the form
element itself, writing a style like this:
input { width: 100% } @element 'form' and (min‐width: 530px) { $this input { width: 50%; float: left; } }
The code is similar to that of the two previous methods, but now we are free to display this search input anywhere — in a sidebar or full width. We can use it in any layout on any website, and no matter how wide the browser is, when the form itself doesn't have enough room to display the inputs side by side, it will adapt to look its best.
Resources For Getting Started
EQCSS-Enabled Template
<!DOCTYPE html> <html> <head> <meta charset="utf‐8"> <title></title> <style></style> </head> <body> <!‐‐[if lt IE 9]><script src="https://elementqueries.com/EQCSS‐polyfills.min.js"></script><![endif]‐‐> <script src="https://elementqueries.com/EQCSS.min.js"></script> </body> </html>
Demos
- Responsive Aspect Ratio
- Sticky Scroll Header
- Blockquote Style
- Kalender
- Content Demo
- Counting Children Demo
- Date Demo
- Zastrow-style Element Query Demo Demo
- Flyout Demo
- Headline Demo
- Media Player Demo
- Message Style Demo
- Modal Demo
- Nav Demo
- Parent Selector Demo
- Pricing Chart Demo
- Responsive Tables Demo
- Scroll-triggered Blocker Demo
- Signup Form Demo
- Testimonials Block Demo
- Tweet-Counter Demo
- JS Variables Demo
- Responsive Scaling Demo
- Geometric Design Demo
- Responsive Order Form
- Element Query Grid
- JS Functions in CSS
- Responsive Content Waterfall
Weiterführende Lektüre
You can find the EQCSS project on GitHub, demos, documentation and articles on the EQCSS website. An ever-growing number of Codepens use EQCSS, and you can create your own pen by forking the batteries-included template that comes hooked up with EQCSS. You can also play with the EQCSS tool that I built to preview if your EQCSS code is working as expected.
Happy hacking!