Flexbox Fallbacks

Aktuell bekomme ich des Öfteren eine Diskussion über den Einsatz von Flexbox in aktuellen Webprojekten mit. Häufiges Thema ist dabei, dass der IE9 Flexbox nicht unterstützt und aus diesem Grund lieber auf Flexbox verzichtet wird. Ich muss zugeben, dass ich seit mehreren Jahren in Mobile- oder Responsive-Projekten arbeite und dort nur äußerst selten noch IE9- oder IE8-Support benötigt wird. Somit kann ich schon länger fast ausschließlich Flexbox verwenden ohne einen Fallback inkludieren zu müssen. Deswegen kann ich die Diskussion vielleicht nicht so nachvollziehen, da Flexbox mittlerweile zu meinen täglichen Tools zählt. In diesem Blog-Post möchte ich mal ein paar typische Flexbox-Fallback-Möglichkeiten skizzieren.

Klar ist – mit CSS Flexbox sind uns Entwicklern neue Möglichkeiten gegeben worden, die bisher nur mit Hacks in CSS zu realisieren waren. Nun können wir verlässlich Inhalte vertikal zentrieren, zueinander ins Verhältnis setzen, visuelle Reihenfolge der Elemente verändern und endlich Boxen mit gleicher Höhe darstellen. Selbst der Browser-Support ist mittlerweile hervorragend (auch Opera-Mini unterstützt nun Flexbox), also kein Grund mehr auf die Vorteile zu verzichten.

Ein klassisches Beispiel für Flexbox ist eine horizontale Navigation. Die Anforderung: egal wie viele Menüpunkte, sie sollen sich optimal den verfügbaren Platz aufteilen.

Beispiel HTML

<nav role="navigation">
    <ul class="the-flextable">
        <li><a href="">Item 1</a></li>
        <li><a href="">Item 2</a></li>
        <li><a href="">Item 3</a></li>
        <li><a href="">Item 4</a></li>
        <li><a href="">Item 5</a></li>
    </ul>
</nav>

Beispiel CSS

.the-flextable {
    display: table; /* Fallback IE<9 */
    display: flex;
    width: 100%;
}

.the-flextable > li {
    display: table-cell; /* Fallback IE<9 */
    flex: 1 1 auto;
    min-width: 1%; /* Fix for Firefox */
}

Codepen-Link: http://codepen.io/maddesigns/pen/NGZJxG

Mit display: table/table-cell; hat man für diese simple Aufgabe einen guten Fallback für Browser die Flexbox nicht verstehen. Selbst vertikal zentrieren des Textes ist mit table-cell möglich.

Vorteile: ‚display: table‘

  • vertikales zentrieren und gleiche Höhen

Nachteil: ‚display: table‘

  • Zwischenräume (margins) können auf table-cell nicht angewendet werden, border-collapse: separate und border-spacing als Ersatz ist nicht optimal

Selbst für Fälle wo flex-wrap zum Einsatz kommt, kann man mit display: inline-block oder float gute Fallbacks erreichen. Nachteil bei inline-block/float ist leider, dass die Höhe der „Flex-Items“ nicht automatisch gleich hoch ist, hier müsste man sich über min-height an das gewünschte Aussehen annähern. Für den Fallback mit display: inline-block ist es zudem notwendig Whitespace, den inline-block mitbringt, zu eliminieren. Der Blogbeitrag von CSS-Tricks zeigt die unterschiedlichen Möglichkeiten. Ich finde die font-size: 0 Methode oft am praktischsten.

Hier mal ein einfaches responsive „floating“ flex-wrap Fallback-Beispiel mit inline-block (hab ich alle buzzwords eingebunden?):

Flexbox Grid

Codepen-Link: http://codepen.io/maddesigns/pen/EBlHd

Vorteile: ‚display: inline-block‘

  • vertikales Zentrieren
  • kein Clearing notwendig

Nachteile: ‚display: inline-block‘

  • keine gleichen Höhen
  • Whitespace-Foo
  • kein Clearing möglich

Vorteile: ‚float‘

  • Verhalten und Anwendung von float ist den meisten Entwickler vertraut

Nachteile: ‚float‘

  • Clearing
  • kein vertikales Zentrieren
  • keine gleiche Höhe

Selbst für einen einfachen Source-Order-Switch kann man auf display: table als Fallback zurückgreifen. Im Blog-Post: Content-Source Ordering habe ich eine Möglichkeit für IE8 & Co. skizziert.

Grundsätzlich bin ich immer ein Freund von mobile first/semantic first, also erst die richtige Source-Order von der Logik her erstellen und dann das gewünschte Ergebnis visuell abbilden.

Ein typisches Beispiel hatte ich letztens im Projekt auch: Ein Kochrezept! Die visuelle Vorgabe für große Viewports (aka Desktop) sah in etwa so aus:

Wireframe Rezeptansicht Desktop

Wireframe Rezept mobile Vorlage

Für Schmalscreens und als Struktur entschied ich mich dazu folgenden Wireframe umzusetzen.

Der Fallback für IE9 (der eigentlich nicht unterstützt wird) ist in dem Fall display: inline-block, allerdings bleibt die logische Reihenfolge der Elemente unverändert. Ich finde das nicht tragisch, optisch sieht es vollkommen in Ordnung aus.

Braucht man aktuell noch alle Flexbox-Varianten?

Flexbox hat einige Spezifikationsvarianten durchlebt und Browserhersteller haben unterschiedliche Schreibweisen implementiert, so dass wir teilweise nicht nur Vendor-Präfixe, sondern auch verschiedene Schreibweisen (Eigenschaftsnamen) für den Cross-Browser-Support einbinden müss(t)en. Autoprefixer nimmt uns das glücklicherweise alles ab. Wenn man alte Android-Versionen unterstützt (4.x ist auch alt ;)), dann benötigt man auf jeden Fall die alte Schreibweise. IE10 braucht die Zwischenlösung von 2012.

Die Tabelle zeigt die verschiedenen Flexbox-Syntaxen und die heutige Schreibweise:
Finale Syntax 2011 Hybrid Syntax 2009 Syntax
display: flex display: flexbox display: box
flex-direction: row box-orient: horizontal box-orient: horizontal
justify-content: flex-start box-pack: start box-pack: start
align-items: flex-start box-align: start box-align: start
flex: 1 flex: 1 box-flex: 1

Mir ist aufgefallen, dass es weniger Probleme gibt, wenn man z.B. mit Modernizr den Support testet und dann dementsprechend die Zuweisung der Eigenschaften macht, heißt also Fallback mit .no-flexbox.

Einen einfacher Test, ob Flexbox (mit Flex-Wrap) verfügbar ist, hat Ethan Marcotte in einem 24ways Artikel gezeigt:

var doc = document.body || document.documentElement;
var style = doc.style;
​
if ( style.webkitFlexWrap == '' ||
    style.msFlexWrap == '' ||
    style.flexWrap == '' ) {
  doc.className += " supports-flex";

Alle Styles werden dann also mit .supports-flex gepräfixt.

CSS-Beispiel:

.supports-flex .flex-container {
    display: flex;
}

.supports-flex .flex-item {
    flex: 1 1 0%;
}

Wie so oft, ist es auch leider so, dass bei der Implementation der Spezifikation Fehler unterlaufen und so gibt es auch für Flexbox Bugs in Browsern. Auch das führt oft zur Ablehnung der Technik. Philip Walton hat die Flexbugs mal zusammengeschrieben.

Die entscheidendsten Bugs sind:

  1. In der vertikalen Flexbox-Ausrichtung mit „column“ wird im IE10–11 die gesetzte Mindesthöhe nicht an die Flex-Items vererbt. Besser wäre es eine definierte Höhe zu setzen.
  2. Chrome, Opera und Safari missachten die per Default vergebene Inhaltsbreite der Flex-Items. Hier empfiehlt es sich den flex-shrink Wert auf 0 statt dem Defaultwert 1 zu setzen um umgewollte Darstellungen zu vermeiden.
  3. Flex-Basis sollte man nicht ohne Einheit in der Flex-Shorthand-Notation benutzen, das führt zu Fehlern im IE10 und 11. Besser ist es 0% anstatt 0px zu verwenden, da einige CSS-Minifizierer 0px zu 0 wandeln (0 ohne Einheit ist ja genau das Problem).

Ein PostCSS-Script hilft uns beim Flexbugs fixen – https://github.com/luisrudge/postcss-flexbugs-fixes. Es scannt das CSS und ersetzt mögliche Problemstellen mit dem empfohlenen Code.

Flexbox-Polyfill für IE8/9

Jonathan Neal, der schon den Polyfill „SVG4everybody“ entwickelt hat, hat mit Flexibility einen Flexbox-Polyfill für IE8 und 9 veröffentlicht. Der Polyfill scannt die Seite und das CSS und stellt das Flexbox-Verhalten mit JavaScript nach. Also kein manueller Aufwand für Entwickler. Als Trigger für JavaScript wird in CSS -js-display: flex; gesetzt.

.foo {
    -js-display: flex;
    display: flex;
}

Um das noch weiter zu Vereinfachen gibt es auch dafür ein PostCSS-Plugin, dass das Einfügen des Triggers -js-display: flex automatisch macht.

Natürlich sollte man genau überprüfen, ob das gewünschte Ergebnis damit auch erzielt wird bzw. ob es notwendig ist dafür extra JavaScript zu verwenden – oft reicht ja auch ein wenig CSS als Fallback aus. Auch wenn das Ergebnis nicht immer 100%ig das Gleiche ist, so gibt es eine Reihe guter Fallbacks für Flexbox – denn müssen Webseiten in jedem Browser gleich aussehen? Nein!

Update 06.04.2016:

Eine sehr schöne Übersicht dazu hat Kenan Yusuf erstellt: Almost complete guide to flexbox (without flexbox)

5 thoughts on “Flexbox Fallbacks”

  1. Wenn man display: inline-block als Fallback nimmt und dann white-space zwischen Elementen eliminieren will, empfehle ich folgendes:

    – word-spacing: -.31em am Container
    – word-spacing: 0 an den Kindern

    Das funktioniert nicht in allen Browsern, aber in allen relevanten, die kein Flexbox unterstützen (also alte IEs). Und es hat den Vorteil, dass man nicht ständig font-size und line-height wieder neu definieren muss.

  2. In meiner Arbeit kann ich sehr oft diesen Satz nicht leben:“denn müssen Webseiten in jedem Browser gleich aussehen? Nein!“
    da gibts CI Vorgaben,die auch in jedem Browser getestet werden und da muss es dann überall gleich aussehen. Die Entscheidungen fallen zu 99% ohne Frontend-Entwickler in der Marketing Abteilung oder in einer externen beauftragten Agentur.

    Und irgendwie versteh ich noch nicht den Unterschied zwischen flex-box Fallbacks und „Hacks“ :-)
    Das Wort „Hacks“ verwendest du bei der altbekannten Technik, das vermutlich schönere Wort „Fallback“ für flex-box der moderneren Technik => aber drumherum Arbeiten tun beide Techniken :-), ob alt oder neu.
    Klar beneid ich dich, wenn du nur solche Kunden hast, die es akzeptieren, dass ihr CI nicht überall gleich aussieht. Ich fühl mich jedoch nicht als Missionarin.

  3. Hi Monika!
    CI-Vorgaben beziehen sich doch meist auf Schrift, Farben und so, selten doch auf Layouts, oder? Fallback bedeutet – welches CSS greift wenn Flexbox im Browser nicht vorhanden ist. Mit einigen Eigenschaften kann man ein gleiches, bis nahezu gleiches Verhalten erreichen. Hacks wären z.B. wenn man mit JS die Höhe der Boxen angleicht, weil es kein Flexbox gibt.

    Und wenn die Entscheidungen zu 99% ohne Frontend-Entwickler fallen, dann ist zu 100% der Workflow falsch -> http://maddesigns.de/responsive-workflow/ ;)

Kommentare sind geschlossen.