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
undborder-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?):
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:
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.
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:
- 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.
- 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. - 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)
Super Artikel :) Flexbox ist für Frontend-Developer eine echt coole Sache!
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.
Das habe ich auch schon ausprobiert, war für mich aber nicht so stabil.
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.
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/ ;)