Suche
Abstraktionen in HTML

Polymorphes Web-UI mit Web Components

Dirk Dorsch

© Shutterstock/wowomnom

Twitter Bootstrap, Zurb Foundation, Material Design, Metro UI oder doch noch das alt bekannte Cupertino? In den letzten Jahren haben sich unterschiedliche Designtrends und damit auch HTML-/CSS-Frameworks etabliert. Die Entscheidung muss früh im Projekt getroffen werden, und es wird sich mit an Sicherheit grenzender Wahrscheinlichkeit herausstellen, dass es die falsche war. Wie kann das Paradigma des „Last Reasonable Moment“ auch bei der Auswahl eines UI-Frameworks angewandt werden? Mit Web Components ist eine Entkopplung von Datenpräsentation und Designstruktur realisierbar, die deutlich über die Möglichkeiten von Style Sheets hinausweist.

Moderne Webapplikationen unterliegen einer immer kürzeren Halbwertszeit, da sich in immer kürzeren Zeiträumen neue UI-Trends etablieren. Nicht zuletzt der Ähnlichkeit im Design vieler Websites sieht man die Marktstellung von Zurb Foundation und Twitter Bootstrap an. Mit der Einführung der neuen Designsprache „Material Design“ durch Google entwickelt sich ein neuer Trend im UI. Was passiert nun mit den auf Basis der responsiven Webdesignplatzhirsche Twitter Bootstrap oder Zurb Foundation entwickelten Applikationen? Was tun mit der in Material Design entwickelten Applikation, wenn in zwei Jahren Apple ein CSS-/JavaScript-Framework auf dem Markt etabliert?

Obwohl in der finalen Umsetzung unterschiedlich, bieten die meisten responsiven Webframeworks ähnliche Konzepte. Alle unterstützen den Entwickler bei der Erstellung von Layouts und setzten für die einzelnen HTML-Elemente ein konsistentes Design und Layout um. Theming-Mechanismen ermöglichen darüber hinaus die Anpassung an die eigenen Designvorstellungen. Auch für anspruchsvolle Effekte wie Pagetransitions, Bilderslideshows oder modale Dialoge sowie Interaktionsgesten wie Drag and Drop haben sich etliche Implementierungen ihren Platz geschaffen. Die Fülle an verfügbaren Frameworks und Bibliotheken macht die Wahl zur Qual. Kaum hat man sich für eines entschieden und die Applikation fast fertig implementiert, erklimmt ein neues Framework den „Hipster-Technologie-Thron“. Wer hip bleiben will, möchte mit dem Projekt also am liebsten nochmal von vorne beginnen.

Mithilfe eines UI-Frameworks ist ein schneller Start des Projekts möglich. Während in der UI-Entwicklung der für die Präsentation der eigenen Geschäftslogik zuständige Code ohnehin meist untrennbar mit dem Look-and-Feel-Code verwoben ist, kommt so noch eine Abhängigkeit zum ausgewählten Framework hinzu. Die Struktur der Applikation ist Frontend-seitig vollständig durch die Vorgaben des UI-Frameworks hinsichtlich der Layout- und Designaspekte vorgegeben. Trotz der Analogien der Konzepte erzwingen alle Frameworks eine gänzlich unterschiedliche Strukturierung des Markup. Soll ein neuer UI-Trend durch Einsatz eines neuen Frameworks berücksichtigt werden, muss die Präsentationsschicht in weiten Teilen neu implementiert werden.

Die Idee

Geht man nun von einer größeren Webapplikation aus, wird diese aus einer nicht geringen Menge von Seiten bestehen, um die sich aus der Geschäftslogik ergebenden Daten zu präsentieren. Die Präsentation soll auf allen Seiten konsistent und mit möglichst geringem Aufwand umgesetzt werden sowie aktuelle Interaktionsparadigmen berücksichtigen. Entsprechend wird die Wahl auf ein UI-Framework fallen. Dies impliziert nun die Abhängigkeit jeder einzelnen Seite vom gewählten Framework. Eine Anpassung an neue UI-Trends muss nun auf allen Unterseiten der Applikation realisiert werden, was mit erheblichen Kosten verbunden sein kann. Web Components können eingesetzt werden, um einheitlich Komponenten für Layout- und Designbelange der Applikation zu kapseln und diese so von der eigentlichen Präsentation zu entkoppeln.

Das Polymer Project ist nicht nur eine Umsetzung der Material-Design-Sprache, sondern darüber hinaus auch ein Framework zur Erzeugung eigener Web Components. Web Components ermöglichen die Definition eigener Komponenten, die wie herkömmliche HTML-Tags im Markup benutzt werden können. So kann mit Polymer ein Set von Webkomponenten definiert werden, das die grundlegenden UI-Elemente aller Frameworks abstrahiert. Das UI wird dann nicht direkt gegen das gewählte UI-Framework, sondern gegen die eigenen Elemente implementiert. Die äußere Gestalt der Applikation lässt sich so ohne Anpassungen der eigentlichen Struktur durch den Austausch geeigneter Web-Component-Implementierungen anpassen.

Zum Zeitpunkt dieses Artikels ist Polymer in der Alpha-Version 0.9.2 erschienen. Diese beinhaltet jedoch noch nicht die Polymer-Elemente für Layout- und Material-Design-Umsetzung. Da Version 0.9.2 im Vergleich zu 0.5, in der die UI-Elemente enthalten sind, starke Änderungen am API bringt, werden im Folgenden die Beispiele soweit möglich auf Basis von Polymer 0.9.2 realisiert.

Die Kandidaten

Sicher existieren insbesondere bei einer Ausweitung auf mobile Themes noch eine Reihe weiterer etablierter UI-Frameworks. Zur Veranschaulichung des Konzepts genügt jedoch eine Beschränkung auf die folgenden drei Kandidaten.

Zurb Foundation, ursprünglich entwickelt, um die hauseigenen Designrichtlinien umzusetzen, wurde es von der Produktdesignfirma Zurb unter der MIT-Lizenz veröffentlicht. Neben den Entwicklungen von Zurb selbst, kommt es unter anderem auf den Websites von National Geographic, der Washington Post oder Mozilla zum Einsatz.

Twitter Bootstrap zielt ebenso wie Foundation auf die Entwicklung responsiver, Mobile-First Webseiten ab. Bootstrap wurde ursprünglich für die Entwicklung interner Tools bei Twitter genutzt und ist ebenfalls unter der MIT-Lizenz erhältlich. Aktuell ist Bootstrap auf GitHub das Projekt mit den meisten Forks und Stars.

Polymer Project ist der jüngste der Kandidaten. Maßgeblich wird es von Google getrieben und kann als Referenzimplementierung der Material-Design-Sprache angesehen werden. Neben der Umsetzung der Designsprache ist Polymer auch ein Framework zur Erstellung von Web Components und wird im Folgenden genutzt, um von sich selbst (und den anderen Kandidaten) zu abstrahieren.

Die Gemeinsamkeiten

Eine der wichtigsten Grundlagen der Frameworks ist die Unterstützung bei der Umsetzung eines geeigneten Layouts. Als Basis hat sich hier das Konzept des Grid-Layouts durchgesetzt. Ein Grid-Layout unterteilt den Screen in Reihen und Spalten. Die Anzahl der Spalten ist hierbei frei wählbar, häufig allerdings auf zwölf beschränkt. Die Reihe stellt sicher, dass alle Zellen innerhalb der Reihe die gleiche Höhe haben.

Sicherlich kann der CSS-Künstler dies mit dem gekonnten Einsatz von float:left, clear:both etc. auch ohne den Einsatz von Fremdbibliotheken erzielen. Allerdings ist ein einfaches Grid-Layout im Allgemeinen nicht ausreichend, da dieses auch responsiv auf die jeweilige Screengröße reagieren muss. Auch hierzu bieten alle Kandidaten Out-of-the-box-Implementierungen, die es ermöglichen, dass sich das Grid der Bildschirmgröße anpasst und die Zellen auf einem Smartphone beispielsweise untereinander statt nebeneinander dargestellt werden.

Neben dem Grid-Layout werden auch die allgemeinen Standardelemente wie Überschriften, Aufzählungen, Links oder Textabschnitte hinsichtlich Schriftgrößen, Abständen etc. in ein konsistentes Design gesetzt. Ebenso lassen sich fortgeschrittene Layoutkonzepte für die Navigation in Form von Navigation Bars, „Hamburger Menu“ oder Tabs finden. Häufig eingesetzte Konzepte wie Listen oder Formulare und die hierin verwendeten Elemente wie Buttons, Dropdowns und andere Eingabefelder werden ebenfalls von den jeweiligen Frameworks einheitlich bereitgestellt.

Neben diesen Basiselementen stehen auch anspruchsvollere UI-Konzepte, wie beispielsweise modale Dialoge und Animationen zur Verfügung. Tabelle 1 gibt einen Überblick einiger ausgewählter gemeinsamer Konzepte und Unterschiede von Bootstrap, Foundation und Polymer.

Tabelle 1: Featureüberblick bei Bootstrap, Foundation, Polymer

Tabelle 1: Featureüberblick bei Bootstrap, Foundation, Polymer

Das Beispiel

Um die Idee einer Layout- und Designabstraktion zu veranschaulichen, soll im Folgenden gezeigt werden, wie ein einfaches Dreispaltenlayout mit Header unter Nutzung aller drei Frameworks implementiert werden kann. Alle Beispiele können hier runtergeladen werden und mit einem aktuellen Chrome-Browser nachvollzogen werden. Um die Möglichkeiten und Grenzen dieses Ansatzes aufzeigen zu können, werden in den einzelnen Spalten eine Liste, ein einfaches Formular, sowie ein Button, der einen modalen Dialog anzeigt, integriert. Der Header soll rechtsbündig ein Dropdown-Menu mit beliebigen Links beinhalten. Bei allen Beispielen wird auf eigenes CSS soweit möglich verzichtet und bereits durch das verwendete Framework ein ansehnliches Ergebnis erzielt. Die Abbildungen 1 und 2 zeigen das Beispiel mit Twitter Bootstrap, beziehungsweise Zurb Foundation.

Abb. 1: Twitter Bootstrap

Abb. 1: Twitter Bootstrap

Abb. 2: Zurb Foundation

Abb. 2: Zurb Foundation

Neben der Abstraktion über die UI-Frameworks können Web Components ebenso genutzt werden, um häufig genutzte Elemente in einfacher Weise wiederzuverwenden. Ein modaler Dialog kann mit unterschiedlichem Inhalt ebenso wie eine Listendarstellung in unterschiedlichem Kontext genutzt werden. Hierzu können eigene Komponenten definiert werden, die die darzustellenden Inhalte übergeben bekommen. Dies kann über die als properties-Attribut des Prototypen publizierten Eigenschaften definiert werden. Angewandt auf das Beispiel wird so zunächst in Listing 1 ein durch die Polymer-Layoutkomponenten motivierter Layoutrahmen definiert. Die in den jeweiligen Layoutbestandteilen anzuzeigenden Inhalte, ebenfalls in Web Components gekapselt, werden in das Layout injiziert.

<!DOCTYPE html>
<html>
  <head> <!-- ... --></head>
  <body>

    <mc-layout>

      <mc-navigation id="nav" label="Meine App"
        menu='{"title":"Aktionen", "actions":[{"label":"Über uns"},
        {"url":"#", "label":"Impressum"}]}'>

      </mc-navigation>

      <div class="teaser">
        <h1>Beispiel Applikationslayout!</h1>
        <p>Das Beispiel zeigt die Verwendung unterschiedlicher Layoutframeworks</p>
      </div>

      <div class="col1">
        <h2>Listenbeispiele</h2>
        <mc-list items='[
          {"heading":"Jaxenter", "url":"http://jaxenter.de",
            "text":"Beschreibung jaxenter"},
          {"heading":"Javamagazin", "url":"http://javamagazin.de",
            "text":"Beschreibung Javamagazin"}]'>
        </mc-list>
      </div>
      <div class="col2">
        <h2>Formulare</h2>
        <mc-form>
          <mc-textfield
            label="Email" placeholder="Enter Email..." type="email" id="mail">
          </mc-textfield>
          <mc-textfield
            label="Pwd" placeholder="Enter Password..." type="password" id="pwd">

          </mc-textfield>
          <mc-button id="submit" text="Anmelden"></mc-button>
        </mc-form>
      </div>
      <div class="col3">
        <h2>Modaler Dialog</h2>
        <mc-dialog header="Achtung Dialog" buttontext="Dialog zeigen">
          <p>Der Dialog Inhalt...</p>
        </mc-dialog>
      </div>
    </mc-layout>

  </body>
</html>

<mc-layout> definiert auf diese Weise das Grundlayout. Die Layoutkomponente bekommt das innere HTML als <content> injiziert und kann dieses an beliebigen Stellen im <template> des Moduls platzieren. Jede implementierende Web Component kann Selektoren nutzen, um die jeweiligen Elemente innerhalb des Layouts zu positionieren. Die Selektion ist über CSS-Selektoren, wie beispielsweise id oder class, möglich. So wird die Navigationsleiste über die id und alle anderen Elemente über ihr classAttribut selektiert. Listing 2 zeigt die beispielhafte Umsetzung des Layouts mit Zurb Foundation.

<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="navigation.html">

<dom-module name="mc-layout" noscript>

  <link href="../../../bower_components/foundation/css/foundation.css" rel="stylesheet">

  <template>

    <content select="#nav"></content>

    <div class="panel">
      <content select=".teaser"></content>
    </div>

    <div class="row">
      <div class="small-1 large-4 columns">
        <content select=".col1"></content>
      </div>

      <div class="small-1 large-4 columns">
        <content select=".col2"></content>
      </div>

      <div class="small-1 large-4 columns">
        <content select=".col3"></content>
      </div>
    </div>
  </template>

  <script>Polymer({is:"mc-layout"})</script>

</dom-module>

<mc-list> stellt den Inhalt in einer Listenform dar. Hierbei ist jedes Listenelement klickbar. Die Inhalte der Liste werden dem items-Attribut als JSON-Array übergeben. Jedes einzelne Element definiert hierbei eine url, eine Überschrift als heading, sowie den eigentlichen text. Über den Data-Binding-Mechanismus werden die entsprechenden Werte in das UI übertragen. Die Liste wird durch den „Template Repeater“ mit dem <template is=“dom-repeat“ items=“{{ items}}“>-Tag aufgebaut. Basierend auf dieser Schnittstelle können so beliebige Inhalte in einer konsistenten Listendarstellung angezeigt werden. Listing 3 setzt diese Listenkomponente auf Basis von Bootstrap um.

<dom-module name="mc-list">

  <link href="../../../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

  <template>
    <div class="list-group">

      <template is="dom-repeat" items="{{items}}">
        <a href="{{item.url}}" class="list-group-item">
          <h4 class="list-group-item-heading">{{item.heading}}</h4>
          <p class="list-group-item-text">{{item.text}}</p>
        </a>
      </template>

    </div>
  </template>

  <script>
    Polymer({
      is:"mc-list",
      properties:{
        items:{type:Array}
      }
    })
  </script>

</dom-module>

<mc-form> zeigt einen alternativen Ansatz. Während bei <mc-list> alle Inhalte in identischer Weise dargestellt werden sollen und sie über ein einfaches JSON-Objekt ausgedrückt werden konnten, besteht ein Formular aus immer unterschiedlichen, variabel angeordneten Eingabefeldern. Die einzelnen Elemente werden ebenso in Komponenten gekapselt. Die <mc-form>-Komponente bekommt den Inhalt als HTML, bestehend aus <mc-textfield> und <mc-button> Komponenten übergeben. In der Foundation-Variante in Listing 4 kann der Inhalt direkt als <content></content> innerhalb der von Foundation vorgegebenen HTML-Struktur platziert werden. Die einzelnen Eingabeelemente sind ebenso in Komponenten abstrahiert. Das Bootstrap <mc-textfield> aus Listing 5 bündelt type, label, und den placeholder in den Attributen und überträgt diese auf ein input-Field mit entsprechendem Label und Platzhaltertext. Darüberhinaus werden die <label> und <input>-Elemente über das umgebende <div> der Klasse form-group in das Bootstrap-Design eingepasst.

<link rel="import" href="../../../bower_components/polymer/polymer.html">

<dom-module name="mc-form">

  <link href="../../../bower_components/foundation/css/foundation.css" rel="stylesheet">

  <template>
    <form>
      <content></content>
    </form>
  </template>

  <script>Polymer({ is:"mc-form" })</script>

</dom-module>

 

<link rel="import" href="../../../bower_components/polymer/polymer.html">

<dom-module name="mc-textfield">

  <link href="../../../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

  <template>

    <div class="form-group">
      <label for="{{id}}" class="col-sm-2 control-label">{{label}}</label>

      <div class="col-sm-10">
        <input type="{{type}}" class="form-control" id="{{id}}" 
          name="{{id}}" placeholder="{{placeholder}}">
      </div>

    </div>
  </template>

  <script>
    Polymer({
      is:"mc-textfield",
      properties:{
        id:{type:String},
        label:{type:String},
        type:{type:String},
        placeholder:{type:String}
      }
    })
  </script>

</dom-module>

<mc-navigation> definiert den Header. Dieser ist bezüglich des Titels parametrisiert und kann innerhalb eines Dropdowns beliebige Aktionen anbieten. Während der Titel als einfacher String im labelAttribut definiert ist, wird das Menü als JSON-Objekt im menu-Attribut übergeben. Das menu-Objekt hat ebenfalls einen title sowie eine Liste von actions, die aus label und url bestehen. Der Inhalt des Dropdowns wird durch Iteration über die actions des menus aufgebaut. In Listing 6 ist die Navigationskomponente mit Twitter Bootstrap umgesetzt.

<link rel="import" href="../../../bower_components/polymer/polymer.html">

<dom-module name="mc-navigation">

  <link href="../../../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

  <template>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="#"><span>{{label}}</span> mit Bootstrap</a>
        </div>

        <ul class="nav navbar-nav navbar-right">
          <li class="dropdown" id="dropdown">

            <a class="dropdown-toggle" data-toggle="dropdown" role="button">
              <span>{{menu.title}}</span>
              <span class="caret"></span>
            </a>
            <ul class="dropdown-menu" id="dropdownmenu" role="menu">
              <template is="dom-repeat" items="{{menu.actions}}">
                <li><a href="{{item.url}}">{{item.label}}</a></li>
              </template>
            </ul>
          </li>
        </ul>
      </div>
    </nav>
  </template>

  <script>
    Polymer(
      {
        is:"mc-navigation",
        properties:{
          menu:{ type:Object },
          label:{ type:String}
        }
    })
  </script>

</dom-module>

<mc-dialog> implementiert einen modalen Dialog. Sowohl der in Listing 7 gezeigte Foundation-Dialog wie auch seine Entsprechung auf Bootstrap-Basis nutzen die jeweiligen JavaScript-Animationen der Frameworks. Hier zeigen sich erste Unwegsamkeiten und Unterschiede in der Umsetzung. Während noch in der Polymer-Version 0.5 die Bootstrap-JavaScript-Magie nicht innerhalb des Shadow DOM einer Komponente angewandt werden konnte, ist dies in Version 0.9.2 problemlos möglich. Durch die Unterschiede im Initialisierungsprozess kann, beziehungsweise muss, das Foundation-JavaScript im eigentlichen HTML-Dokument geladen und initialisiert werden, während sich Bootstrap innerhalb der Komponenten, die es benötigen, laden lässt.

<link rel="import" href="../../../bower_components/polymer/polymer.html">

<dom-module name="mc-dialog">

  <link href="../../../bower_components/foundation/css/foundation.css" rel="stylesheet">

  <template>

    <a href="#" data-reveal-id="myModal" class="button">{{buttontext}}</a>

    <div id="myModal" class="reveal-modal" data-reveal>
      <h2 id="modalTitle">{{header}}</h2>
      <content></content>
    </div>
    
  </template>

  <script>
    Polymer({
      is: "mc-dialog",
      properties: {
        header: {type: String},
        buttontext: {type: String}
      }
    });
  </script>

</dom-module>

Um den Wechsel zwischen den Implementierungen noch einfacher zu gestalten, können die einzelnen HTML-Importe in einer dedizierten Datei gekapselt werden. Somit genügt der Austausch einiger weniger Zeilen, um das gesamte Aussehen des UI anzupassen. Listing 8 zeigt nochmals den vollständigen Rahmen, in den Listing 1 eingebettet ist.

<!DOCTYPE html>
<html>
  <head>

    <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>

    <!-- Twitter Bootstrap -->
    <link rel="import" href="components/bootstrap/components.html">
    <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- Zurb Foundation -->
    <!--<link rel="import" href="components/foundation/components.html">-->
    <!--<link rel="stylesheet" href="bower_components/foundation/css/foundation.css">-->

    <!-- Polymer -->
    <!--<link rel="import" href="components/polymer/components.html">-->
  </head>
  <body>

    <mc-layout> <!-- siehe Listing 1 --> </mc-layout>
    
    <!-- Initialisierung Foundation -->
    <script src="bower_components/jquery/dist/jquery.min.js"></script>
    <script src="bower_components/foundation/js/foundation.min.js"></script>
    
    <script>
      $(document).foundation();
    </script>

  </body>
</html>

Der neue Look

Auch ohne den Wunsch mehrerer austauschbarer Implementierungen des UI zeigt das Beispiel die saubere Trennung der Datenpräsentation von Layout- und Designbelangen. Während die Präsentation in Listing 1 gegen ein definiertes Komponenten-API implementiert ist, sind die Darstellungsbelange in den einzelnen Komponenten gekapselt. So lassen sich auch über reines CSS hinausgehende Anpassungen an einzelnen Elementen an einer zentralen Stelle, ohne Eingriff in die eigentliche Datenpräsentation, ermöglichen. Um zu illustrieren, wie durch diese Struktur eine drastische Anpassung der Interaktion möglich ist, realisiert Listing 9 das in Abbildung 3 gezeigte Layout auf Basis von Polymer 0.5 [Anmerkung: Da zum Zeitpunkt der Fertigstellung dieses Artikels in der Version 0.9.2 von Polymer die Polymer-Elemente noch nicht verfügbar waren, basiert dieses Beispiel auf Polymer 0.5.5].

Abb. 3: Alternatives Layout mit Polymer 0.5

Abb. 3: Alternatives Layout mit Polymer 0.5

Abb. 4: Polymer 0.5 auf kleinem Screen

Abb. 4: Polymer 0.5 auf kleinem Screen

Das neue Layout ist bezüglich der „Schnittstelle“ vollständig kompatibel und somit mit obigen Bootstrap- und Foundation-Varianten austauschbar (abgesehen vom Polymer-Versionskonflikt). Die Inhalte des Dropdowns aus dem Header werden in ein linksseitiges Menü verlagert. Auf Basis des Polymer-<core-scaffold>-Elements ist das Layout bereits responsiv und auf kleinen Bildschirmen auf einen („Hamburger“-)Menübutton reduziert (Abb. 4). Durch eine <core-media-query> und deren Auswertung wird der Inhalt je nach Bildschirmgröße unter- oder nebeneinander angezeigt.

Um die bereits definierte Schnittstelle nicht anpassen zu müssen, ist allerdings ein Workaround notwendig. Die Schnittstellen des Beispiels sind so gewählt, dass das Menü sowie der Applikationstitel dem <mc-navigation>-Element übergeben werden. Die alternative Layoutkomponente muss diese Informationen jedoch im linksseitigen Menü darstellen und benötigt daher den Zugriff auf die dem <mc-navigation>-Element übergebenen Attribute. Um die Schnittstelle im Nachhinein nicht anpassen zu müssen, nutzt Listing 10 die Lifecycle-Methode ready der <mc-navigation>-Komponente, um die benötigten Informationen in der globalen Variable window.nav zugänglich zu machen. Die im Prototyp der neuen <mc-layout>-Komponente definierten Funktionen getMenu und getLabel lesen diese Variable aus und machen sie für das Data Binding zugänglich.

<!-- imports -->
<polymer-element name="mc-layout">
  <template>
    <style>
      .container {
        padding:12px;
        background: #ffffff;
      }
      .jumbotron {
        padding:24px;
      }
    </style>

    <!-- Media Query, um kleine Bildschirme zu erkennen -->
    <core-media-query query="max-width:480px" queryMatches="{{smallScreen}}">
    </core-media-query>

    <core-scaffold>
      <core-header-panel navigation flex>

        <core-toolbar id="navheader"> <span>{{getLabel()}}</span></core-toolbar>

        <core-menu selected="0" >
          <core-submenu label="{{getMenu().title}}">
            <template repeat="{{item in getMenu().actions}}">
              <core-item><paper-button>{{item.label}}</paper-button></core-item>
            </template>
          </core-submenu>
        </core-menu>
      </core-header-panel>

      <!-- Titel nur auf kleinen Bildschirmen anzeigen -->
      <div  tool horizontal layout start center class="fill">
        <div hidden?="{{!smallScreen}}">{{getLabel()}}</div>
      </div>

      <paper-shadow class="jumbotron" vertical layout start start z="2">
        <content select=".teaser"></content>
      </paper-shadow>

      <!-- auf großen Bildschirmen nebeneinander, auf kleinen untereinander -->
      <div class="container" horizontal?="{{!smallScreen}}" layout start-start>
        <div class="container" flex vertical layout>
          <content select=".col1"></content>
        </div>
        <div class="container" flex vertical layout>
          <content select=".col2"></content>
        </div>
        <div class="container" flex vertical layout>
          <content select=".col3"></content>
        </div>
      </div>
    </core-scaffold>

  </template>

  <script>
    Polymer({
      getMenu: function() {
        return window.nav.menu;
      },
      getLabel: function() {
        return window.nav.label;
      }
    })
  </script>

</polymer-element>

 

Polymer({
  ready:function(){
    window.nav = {
      label:this.label,
      menu:JSON.parse( this.menu )
    };
  }
})

Eine elegantere Möglichkeit ergibt sich, wenn die Schnittstellen noch angepasst werden können. Der Workaround zeigt allerdings, dass so auch im Nachhinein noch weitere, alternative Darstellungen geschaffen werden können, ohne dass für die eigentliche Struktur der Datenpräsentation angepasst werden muss. Dennoch stellt man an dieser Stelle fest, dass das „API-Design“ der Komponenten nicht gut gewählt war und dieses modifiziert werden musste. Die Schnittstellen von <mc-layout> und <mc-navigation> können bezüglich der Parameter leicht vereinheitlicht werden, sodass die Inhalte an die Layoutkomponente übergeben und innerhalb der jeweiligen Implementierungen an die entsprechenden Navigationskomponenten weitergereicht werden.

Fazit

Das Beispiel der Abstraktion über unterschiedliche UI-Frameworks sollte zeigen, was mit Web Components möglich ist. Ein wesentlicher Aspekt ist die dadurch realisierbare Trennung von Struktur und Inhalt und die damit verbundene Möglichkeit, strukturelle Anpassungen an wohldefinierter Stelle vornehmen zu können. Dies ermöglicht die Definition von Design- und Layoutkomponenten, die als firmenweite UI-Bibliothek eingesetzt werden können. Durch die polymorphen Eigenschaften lassen sich diese dann dennoch dem jeweiligen Einsatzszenario flexibel anpassen. Auch lassen sich Browser-/Device-abhängige UI-Implementierungen realisieren, die über gewöhnliche responsive Webseiten hinausgehen. Bereits mit Polymer 0.5.5 lassen sich verhältnismäßig stabile Anwendungen realisieren. Im Laufe des ersten Halbjahres wird vermutlich eine über den alpha-Status hinausgehende Version 0.9.2 verfügbar sein. Nicht zuletzt diese wird die Vorfreude auf das erste finale 1.0-Release wecken.

Aufmacherbild: Vector illustration of mechanism von Shutterstock / Urheberrecht: wowomnom

Verwandte Themen:

Geschrieben von
Dirk Dorsch
Dirk Dorsch
Dirk hat seit 2008 nahezu alle Rollen in der Java-basierten (mobile) Enterprise-Entwicklung durchgemacht. In den Jahren als Entwicklungsleiter vermisste er das Hands-on und legt nun den Fokus wieder auf die Entwicklung.
Kommentare

Hinterlasse einen Kommentar

2 Kommentare auf "Polymorphes Web-UI mit Web Components"

avatar
400
  Subscribe  
Benachrichtige mich zu:
volkix
Gast

Vielleicht hätte man den Artikel etwas früher veröffentlichen sollen. Polymer 0.9.2 Alpha ist nun doch schon ein halbes Jahr alt….
Aktuelle Version ist 1.2.1.
Was soll man mit so einem Artikel noch anfangen?

Dirk Dorsch
Gast

Hallo volkix,

in der Tat ist Polxmer schon um einiges weiter. Der Artikel erschien ursprünglich im Juni im Javamagazin. In der Tat hätte man den Artikel vor der Veröffentlichung hier aktualisieren sollen…

Viele Grüße
Dirk Dorsch