Bild: K.G.Hawes - http://www.flickr.com/photos/kennethhawes/6124182221/

Ionic: Das Frontend-Framework unter der Lupe

Vor einigen Wochen hat eine Ankündigung für Furore gesorgt - Ionic, ein Framework für die Entwicklung mobiler Apps in HTML5, stand kurz der Veröffentlichung. Zwischendurch gab es als kleine "Anfütterung" schonmal den zugehörigen Icon-Font "ionicons". Und nun ist auch das Framework (GitHub-Repository) selbst in der Alpha-Version erschienen.

Beides wurde unter MIT-Lizenz veröffentlicht und steht somit für kommerzielle wie nicht-kommerzielle Projekte zur Verfügung.

Was will das Framework? Und was nicht?

Ionic is a beautiful front-end framework for developing hybrid mobile apps in HTML5.

Ionic versteht sich als Frontend-Framework, mithilfe dessen mobile Hybrid-Apps auf Basis von HTML5 entwickelt werden können. Laut Aussage der Entwickler hat sich die HTML5-Landschaft in den letzten Jahren soweit verbessert, dass dem Plan, eine native, mobile App mit HTML, CSS und JavaScript zu bauen, eigentlich nichts mehr im Wege steht.

Ionic versucht dabei alles an technischen Grundlagen für die eigentliche App zu liefern. Neben Layout-Komponenten für Statusleisten, Listen, Formulare, etc., wie man sie aus CSS-Frameworks - z. B. Zurb Foundation oder Bootstrap - kennt, sind das vor allem auch JavaScript-basierte Komponenten, die das Bauen und Konfigurieren eines klassischen Mobile-App-Interfaces vereinfachen.

Das anschließende Packaging der fertigen App kann dann mithilfe von Cordova/Phonegap oder einem vergleichbaren Tool passieren. Hier macht Ionic keine Vorgaben. Die Präferenz der Entwickler liegt jedoch bei Cordova und Phonegap; so sind bspw. für die nahe Zukunft eigene Cordova-/Phonegap-Plugins vom Entwicklerteam angekündigt.

Was das Ionic-Framework nach Bekunden der Entwickler nicht sein möchte, ist ein Baukasten für mobile Webseiten. Das ist ein hehrer Ansatz und durchaus vertretbar. Allerdings sprechen wir hier von Web-Standards - es kann einem also niemand verbieten, die mit Ionic gebaute App auf seinen Server zu laden und sie als Web-App anzubieten, ohne den lästigen Umweg über irgendwelche App-Stores zu gehen.

Was steckt technisch dahinter?

Ionic setzt in Sachen Styles auf SASS. Das kann einem theoretisch egal sein, möchte man nur additiv ein paar eigene Style-Angaben hinzufügen. In diesem Fall reicht es, eine eigene CSS-Datei zu erstellen und zusätzlich einzubinden.

Möchte man jedoch tiefgreifendere Anpassungen am Design des Frameworks vornehmen, empfiehlt es sich ebenfalls SASS bzw. SCSS zu schreiben. Dadurch hat man die Möglichkeit, die ausschweifende Liste an SASS-Variablen, die Ionic mitbringt, zu verändern/überschreiben. Typografische Angaben, Farben, Abstände, etc. lassen sich dadurch anpassen, ohne dass auch nur eine physische CSS-Klasse referenziert werden müsste.

Möchte man weitergehende Änderungen machen und - aufbauend auf den Ionic-Styles - eigene Styles definieren, gibt es eine umfangreiche Sammlung an Mixins, die einem das Leben leichter machen. So muss man sich bspw. um Vendor-Prefixes in der Regel keine Sorgen machen. Und reicht einem das mitgelieferte, auf CSS-Flexbox basierende Grid-System nicht aus, gibt es eine Sammlung Mixins für den Umgang mit Flexbox-Layouts.

Auf HTML-/JavaScript-Seite setzt Ionic auf AngularJS, welches sich selbst als HTML-Erweiterung sieht. Und in der Form wird es auch eingesetzt, wobei Angular-Direktiven eine maßgeliche Rolle spielen. Allerlei Custom Elements, wie <content>, <header-bar>, <tabs>, etc., sind vordefiniert und erleichtern den Bau des Interfaces. Konfigurationen, Data- und Event-Bindings können wie gewohnt über die Angular-eigenen und Ionic-spezifische HTML-Attribute vorgenommen werden.

Wie fängt man an?

Für den Start gibt es zwei Alternativen:

1. Der klassische Download

Die unterschiedlichen Releases können direkt von der Ionic-GitHub-Seite bezogen werden. Alternativ kann das Projekt natürlich auch geklont werden. Wie man es auch macht, man erhält das komplette Projekt mit allen Source Files, Tests und was sonst noch so dazu gehört zu einem ernst zu nehmenden GitHub-Repository.

Alternativ kann man das Corduva-Seed-Projekt runterladen. Dieses ist aufgeräumter, enthält nur fertig kompilierte CSS-Dateien und ist bereits in die für Cordova/Phonegap charakteristische Ordner-Struktur eingebettet. Für einen schnellen Start zur Orientierung ist das Seed-Projekt sicherlich die beste Wahl.

2. Das Ionic-Command-Line-Tool

Ionic bietet außerdem ein auf Node.js basierendes Command-Line-Tool. Installiert wird es folgendermaßen (Voraussetzungen sind Node.js und NPM):

$ npm install -g ionic

Mac-User stellen dem Befehl noch ein sudo voran.

Das Comand-Line-Tool bietet bisher nur einen Befehl, aber der reicht für den Anfang auch:

$ ionic start my-project

Dies legt einen Ordner "my-project" an und lädt die Inhalte des Seed-Projekts hinein.

Ein Seed-Projekt mit Grunt- und SASS-Integration gibt es momentan leider noch nicht, so dass man mit dem Command-Line-Tool noch nicht wirklich weit kommt, möchte man Ionic in Verbindung mit eigenen SASS-Styles verwenden. In diesem Fall muss man sich aus dem Haupt-Repository bedienen und sich alles etwas zurecht schieben.

Entwickeln mit Ionic

Hat man das Seed-Projekt geladen, kann man sich mithilfe der zahlreichen Komponenten und Direktiven austoben. Beispielhaft möchte ich hier zwei Komponenten vorstellen, die ganz gut das Leistungsspektrum von Ionic demonstrieren.

Off-Canvas-Menu

Das Off-Canvas-Menu (im Ionic-Kontext "Side-Menu" genannt) bietet zwei Off-Canvas-Bereiche - links und rechts. Ob man einen oder beide nutzt, bleibt den eigenen Vorlieben überlassen. Dank der Integration von Hammer.js lässt sich das Side-Menu überdies per Swipe-Geste öffnen. Trotzdem bietet sich natürlich ein Toggle-Button an, da Nutzer selten etwas öffnen, von dessen Existenz sie nicht wissen.

Das Markup für das Side-Menu sieht folgendermaßen aus:

<body ng-app="side-menu-demo" ng-controller="AppCtrl">
    <side-menus>
        <pane side-menu-content>
            <header-bar type="bar-positive"
                title="'Side-Menu-Demo'"
                left-buttons="headerLeftBtns"></header-bar>
            <content> ... </content>
        </pane>
        <side-menu side="left">
            <!-- Menu-Inhalt ... -->
        </side-menu>
    </side-menus>
</body>

Zusätzlich benötigen wir den AppCtrl, um einen Toggle-Button zu integrieren.

<script>
    angular
        .module('side-menu-demo', ['ionic'])
        .controller('AppCtrl', function ($scope) {
            $scope.headerLeftBtns = [{
                type: 'button-icon',
                content: '<i class="icon ion-navicon"></i>',
                click: function () {
                    $scope.sideMenuController.toggleLeft();
                }
            }];
        });
</script>

Intern iteriert die headerBar-Direktive über die Buttons. Daher muss ein Array übergeben werden, auch wenn im Beispiel nur ein Button benötigt wird.

Möchte man alternativ/zusätzlich ein rechtsseitiges Side-Menu integrieren, bedient man sich im HTML des side-Attributs (<side-menu side="right"> ...) und ruft zum Öffnen/Schließen im Controller die sideMenuController.toggleRight-Methode auf.

Modal

Ionic bietet ein Modal-Element - eine Ebene, die sich über den gesamten Bildschirm schiebt und eigene Inhalte enthält. Für Bereitstellung der Funktionalität steht eine Modal-Factory zur Verfügung.

Für ein Modal benötigen wir ein Template und eine Prise Controller-Logik. Ein beispielhaftes Template (abgelegt unter templates/modal.html) könnte wie folgt aussehen:

<content class="modal>
    <h2>Modals rock!</h2>
    <!-- Content ... -->
    <button class="button button-block button-dark" ng-click="toggleModal('hide')">
        <i class="icon ion-arrow-down-b"></i> Toggle
    </button>
</content>

Irgendwo in der App müsste außerdem ein Button mit dem Attribut ng-click="toggleModal('show')" hinterlegt sein, um das Modal einblenden zu können.

Die zugehörige Logik im AppCtrl sähe dann z. B. so aus:

angular
    .module('modal-demo', ['ionic'])
    .controller('AppCtrl', function ($scope, Modal) {

        // Initial ohne Funktion
        $scope.toggleModal = angular.noop;

        // Sobald das Modal instanziiert ist, kommt die Funktionalität
        function bindClick(modal) {
            $scope.toggleModal = function (action) {
                modal[action]();
            };
        }

        // Instanziieren des Modal-Objekts
        Modal.fromTemplateUrl('templates/modal.html', bindClick, {
            scope: $scope,
            animation: 'slide-in-up'
        });

    });

Wir injizieren die Modal-Factory in den Controller und rufen die fromTemplateUrl-Methode auf. Diese lädt das Template über den angegebenen Pfad. Da es sich dabei um einen asynchronen Prozess handelt, muss eine Callback-Funktion definiert werden. Dieser wird das instanziierte Modal-Objekt anschließend übergeben. Als dritten Parameter bekommt die fromTemplateUrl-Methode ein Options-Objekt, in welchem ein Scope übergeben werden kann und die Art der Animation festgelegt wird.

In obigem Code hat die toggleModal-Methode im $scope erstmal keine Funktionalität, da das Modal zur Initialisierung noch nicht fertig instanziiert ist. In der Callback-Funktion, bindClick, wird dann das Öffnen und Schließen des Modals mit der toggleModal-Methode verknüpft.

Etwas weniger umständlich kann man es handhaben, wenn man auf ein Inline-Template zurückgreift:

<script id="modal-tpl" type="text/ng-template">
    <content class="modal">
        <!-- Modal-Content ... -->
    </content>
</script>

Dieses wird einfach in der index.html irgendwo abgelegt. Über die Id modal-tpl kann dann innerhalb des Controllers auf das Template zugegriffen werden:

angular
    .module('modal-demo', ['ionic'])
    .controller('AppCtrl', function ($scope, Modal) {

        var tplModal = document.getElementById('modal-tpl')
                .innerHTML
                .replace(/(^\s+)/, '');

        $scope.modal = Modal.fromTemplate(tplModal, {
            scope: $scope,
            animation: 'slide-in-up'
        });

        $scope.toggleModal = function (action) {
            $scope.modal[action]();
        };

    });

Als erstes wird das Template beschafft. Da ich kein Anhänger von jQuery im Angular-Kontext bin, greife ich auf document.getElementById zurück und hole mir das Template-MarkUp per innerHTML. Anschließend entferne ich führende Leerzeichen aus dem Template-String, da sonst die $compile-Methode von Angular einen Fehler wirft (mehr dazu hier).

Danach instanziiere ich das Modal mithilfe der fromTemplate-Methode. Da nichts geladen werden muss, kommt man hier ohne Callback-Funktion aus. Einfach neben dem Template-String noch das Options-Objekt übergeben, die Methode gibt dann direkt das Modal-Objekt zurück, welches in der $scope.modal-Eigenschaft gespeichert wird.

Ein weiterer Vorteil der synchronen Vorgehensweise der fromTemplate-Methode ist, dass wir das Event-Binding zum Ein- und Ausblenden des Modals direkt vornehmen können, und nicht in eine Callback-Methode auslagern müssen.

Weitere Komponenten

Ionic bietet natürlich noch mehr. Wobei der Umfang in naher Zukunft zunehmen dürfte. Am besten bekommt man einen Überblick, indem man sich einmal durch die Sammlung klickt: Ionic-Controllers.

Fazit

Das Ionic-Framework ist im Alpha-Status und das merkt man ihm zuweilen auch an. Ich habe als Testgeräte ein Nexus 4 (Android 4.3/Chrome 31) und ein iPhone 5s (iOS7/Safari) genutzt. Die Transitions (bspw. beim Side-Menu) liefen daher auch relativ rund.

Was gar nicht recht funktionieren wollte, war das Custom Scrolling. An der Stelle muss auf jeden Fall noch nachgebessert werden. Auch der Zurück-Button verschwindet derzeit noch nicht immer, auch wenn er das sollte. Es gibt einfach noch Stellen, wo die Funktionalität auf ein solideres Fundament gestellt werden muss.

Aber das ist okay, dafür gibt es ja Bug Reports und Pull Requests.

Grundsätzlich kann man aber sagen, dass sich hier ein interessantes Framework neben jQuery Mobile, Sencha Touch und LungoJS positioniert. Das Angebot an Komponenten und Direktiven ist schon sehr brauchbar und wird in Zukunft sicherlich noch erweitert werden. Die momentane Ausrichtung auf iOS7 ist natürlich suboptimal im Kontext von Multiplattform-Hybrid-Apps, aber an der Front wird sich wohl auch noch was tun. Außerdem ist das Design relativ dezent, so dass dieser Makel zu verkraften ist.

Ein großer Pluspunkt dürfte die Entscheidung für AngularJS sein. Ein Framework, welches ganz vorn dabei ist, wenn es um die Entwicklung von Single-Page-Applications geht. Wobei es nicht so überladen wie bspw. Sencha Touch ist. Hält der Hype um Angular an, kann dies Ionic nur zum Vorteil gereichen.

Man darf also gespannt sein, wie es weiter geht, wenn Ionic dem Alpha-Stadium entwachsen ist.