Ich habe mich die letzte Zeit intensiv mit Web Components (via Polymer) und aktuellen Webstandards rund um Responsive Design befasst. Eigentlich, so denkt man zunächst, bräuchte es auch für Web Components neue Responsive-Design-Webstandards. Das heutige Arbeitspferd für Responsive Design sind Media Queries, die (neben vielen anderen Nachteilen) den Haken haben, sich nur auf die Maße der gesamten Webseite bzw. des gesamten Devices beziehen zu können. Der reinen Lehre nach sollte eine Komponente aber komplett unabhängig vom Rest der Webseite sein, d.h. selbst entscheiden wann sie sich für weniger oder mehr Platz umbaut. Das ist allerdings nicht ganz einfach – nicht zuletzt, weil das eigentlich überhaupt gar nicht geht. Und ich glaube auch nicht, dass man das haben will.
Was eine wirklich komplett unabhängige Komponente bräuchte, wären nicht herkömmliche Media Queries zur Abfrage der Gesamtbreite von Device oder Webseite, sondern etwas zur Abfrage von der Breite eines bestimmten Elements (d.h. von sich selbst). Ein solches Feature hieße dann Element Query und trägt in sich das kleine Problem, dass es nicht funktioniert. Tab Atkins legt die Gründe hier und hier dar. Es gibt eine Vielzahl an konzeptionellen Problemen zu überwinden und wenn Element Queries auch nicht völlig unmöglich sind, so sind sie doch selbst im besten Fall noch viele Jahre von der Einsatzreife entfernt. Nicht nur gibt es keine Browserunterstützung, es gibt noch nicht mal einen konkreten Plan wie ein solches Feature überhaupt aussehen könnte.
Dessen ungeachtet gibt es diverse Prollyfills, die mit dem Element-Query-Konzept experimentieren. Wirklich ausgereift scheint mir keins dieser Scripts zu sein und insbesondere in Web Components konnte ich keinen der Kandidaten überzeugend zum Funktionieren bewegen. Und während ich noch damit herumspielte kam mir der Gedanke, dass man vielleicht gar keine Element Queries in Web Components haben möchte.
Zum einen stellt sich die Frage, ob man eine Responsive-Funktionalität, die so ausgefeilt wie Media Queries ist, überhaupt in seiner Komponente braucht. Dinge wie die Schriftgröße werden ohnehin von der umgebenden Webseite auf die Komponente vererbt – schrumpft die Schriftgröße via Media Query auf der Seite, so schrumpft sie auch in der Komponente. Sind Layout-Maße mit schriftgrößen-relativen Einheiten festgelegt, reduzieren auch sie sich gleich mit. Und baut man das Komponenten-Layout mit Flexbox, so kann man zumindest einfache Layout-Umbauten (z.B. den Wechsel zwischen einem Zwei- und Einspalten-Design) nur über Mindestmaße und flex-wrap
, also ganz ohne Media Queries abbilden. Außerdem könnte ein Webdesigner mit entsprechenden Pseudoklassen direkt ins Shadow DOM hineingreifen um vor Ort und Stelle punktuelle CSS-Änderungen anzubringen. Häufig könnte das allein schon reichen aber selbst wenn nicht, weiß ich nicht, ob man Komponenten mit jeweils eigenen Element Queries haben will.
Wenn Komponenten gemäß der reinen Lehre sich komplett selbst managen und sie auch selbst via Element Query entscheiden, wann sie sich responsive rearrangieren, geht dem Webdesigner ein großes Stück Kontrolle verloren. Wo die Breakpoints für das Design der Webseite sitzen, würden dann plötzlich die Entwickler der Komponenten entscheiden! Das entsprecht aber eigentlich auch der reinen Lehre – wo kommen wir denn hin, wenn angeblich komplett in sich gekapselte Komponenten über das Aussehen der gesamten Webseite entscheiden? Ohnehin: so lange es keine nativen Element Queries gibt, müsste jede Komponente seine eigene Responsive-Logik in JS mitschleppen. Jeder Teil der Webseite hätte dann sein eigenes kleines Gehirn (inklusive eigener Bugs) und sein eigenes kleines Design und alles sieht aus (und resized sich) wie Kraut und Rüben. Das kann eigentlich nicht die Lösung sein.
Aktuell erscheint es mir am Sinnvollsten, dass (mit JavaScript) auf der Webseite eine zentrale Responsive-Steuerung eingerichtet wird. Die Komponenten haben mehrere Layouts an Bord, entscheiden aber nicht selbst, wann welches Aussehen verwendet wird. Das regelt die zentrale Steuerung per Attributvergabe an die Komponenten. So bleibt alles inklusive der Komponenten schön responsive, aber die Breakpoints werden zentral gesteuert. Das, kombiniert mit den schon erwähnten Responsive-Automatismen (Flexbox, Schriftgröße) könnte ein schönes gemeinsames Bild ergeben. Und nicht zuletzt funktioniert eine solche Konstruktion ohne Wenn und Aber in modernen Browsern.
Zur Umsetzung dieses Prinzips muss eine Komponente (gebaut mit Polymer oder anderweitig) nur ein entsprechendes layout
-Attribut unterstützen und sein Aussehen in Abhängigkeit davon regeln. Das ist zumindest in Polymer-Elementen recht unkompliziert:
<link rel="import" href="bower_components/polymer/polymer.html"> <polymer-element name="x-layouts" attributes="layout" noscript> <template> <style> :host { display: block; } :host([layout="large"]) { color: red; } :host([layout="medium"]) { color: green; } :host([layout="small"]) { color: blue; } </style> <p> Hallo Welt! </p> </template> </polymer-element>
Das Element unterstützt ein layout
-Attribut mit den drei Werten small
, medium
und large
und passt sein Aussehen mit dem Element-eigenen CSS an. Das Setzen dieses Attributs übernimmt dann einfach die Webseite, die das Element einbindet:
<!doctype html> <title>Responsive Komponente</title> <meta charset="utf-8"> <script src="bower_components/platform/platform.js"></script> <link rel="import" href="x-layouts.html"> <x-layouts class="responsiveComponent"></x-layouts> <script> var components = document.querySelectorAll('.responsiveComponent'); var isLarge = window.matchMedia('(min-width: 600px)'); var isMedium = window.matchMedia('(min-width: 400px)'); var isSmall = window.matchMedia('(max-width: 400px)'); function resize(){ var layout = (isLarge.matches) ? 'large' : (isMedium.matches) ? 'medium' : 'small'; for(var i = 0; i < components.length; i++){ components[i].setAttribute('layout', layout); } } window.addEventListener('resize', resize); window.addEventListener('load', resize); </script>
Und das war es schon! Wenn man einen Haufen selbstentwickelter Komponenten hat, die alle das layout
-Attribut unterstützen, braucht man keine einzige Code-Zeile mehr als das. Das einzig etwas abgefahrenere Feature in dieser Konstruktion ist window.matchMedia()
, was aber außer in alten IE überall funktioniert und für die IE gibt es bekanntlich einen Polyfill. Für umfassende Unterstützung ist also gesorgt.
Zusammengefasst vereint diese Art von responsiven Komponenten mehrere Vorteile: sie funktionieren (im Gegensatz zu Element Queries) in jedem modernen Browser, erlauben die Zentralisierung der Breakpoint-Steuerung (im Gegensatz zu autonom entscheidenden Komponenten) und sind, wenn die Grundfunktion einmal implementiert ist, sehr einfach zu benutzen – vor allem wenn man bedenkt, dass man Polymer-Elemente von anderen Elementen erben lassen kann. Der Haken an der Geschichte ist, dass natürlich nie alle Komponenten auf dieser Welt eine einheitliche layout
-Attribut-Unterstützung haben werden, sondern dass man damit vornehmlich eigene Komponenten wird ausrüsten können. Aber wenn man bedenkt, dass sich heutzutage die meisten Komponenten überhaupt gar nicht um das Responsive-Thema kümmern, ist das eigentlich kein wirklicher Rückschritt.