Webkrauts Logo

Webkrauts Webkrauts Schriftzug

- für mehr Qualität im Web

Eine Extrawurst für oldIE

SASS für ältere IE nutzen

Eine Extrawurst für oldIE

Die alten Internet Explorer bis Version 8 haben viele Techniken nicht implementiert, die Webworker heute gerne und oft nutzen. In solchen Fällen kann der Präprozessor SASS hilfreich sein, um den alten IE – ohne viel zusätzliche Arbeit – eine Extrawurst zu braten.

Die Nutzung moderner Techniken im Frontend ist nicht mehr ungewöhnlich. Die meisten dieser Techniken werden von älteren IE (bis inklusive Version 8) nicht unterstützt. Manche haben allerdings ein IE-spezifisches Pendant. Deshalb sind Webworker immer wieder in der Situation, oldIE (IE 8 und früher) eigene Styles zuweisen zu wollen.

Wollt ihr euch nicht nur auf Hacks verlassen, könnt ihr einen Präprozessor wie Sass für diese Zwecke nutzen. Dadurch befreit ihr gleichzeitig das CSS für die richtigen Browser von altem Ballast und Hacks. Das Prinzip ist dabei einfach.

Ich lass Dich nicht rein

Als allererstes müsst ihr verhindern, dass oldIE das gleiche Stylesheet liest wie alle modernen Browser. Denn schließlich möchtet ihr nicht ein globales CSS durch ein IE-spezifisches ergänzen, ihr möchtet zwei getrennte Welten schaffen. Dafür bindet ihr das CSS folgendermassen ein:

  1. <!-- Dieses CSS wird vom oldIE definitiv nicht gelesen -->
  2. <link rel="stylesheet" href="css/styles.css" media="all and (min-width: 0px)">
  3.  
  4. <!--[if lte IE 8]>
  5.     <link rel="stylesheet" href="css/oldie.css">
  6. <![endif]-->

Zuerst verlinkt ihr styles.css mit einer Media Query, die den alten IE davon abhält, diese Datei herunterzuladen. Danach verlinkt ihr für oldIE ein spezielles CSS innerhalb eines Conditional Comment. Getrennte CSS-Dateien für IE7 und IE8 solltet ihr vermeiden, sie würden den Pflegeaufwand unnötig erhöhen. Zudem könnt ihr zwischen beiden Versionen prima mit dem Star-Plus-Hack unterscheiden. Und nicht zuletzt werden die IE7-Nutzer immer weniger, und nur der IE8 wird noch ein Weilchen als Pflegefall verbleiben.

Auf diese Weise weist ihr zwei CSS-Dateien sauber voneinander getrennt zu. Doch eigentlich wollt ihr effektiv nur an einer CSS-Datei arbeiten. Deshalb müsst ihr den nächsten Schritt tun.

Variablen

Die Unterscheidung zwischen »für oldIE« und »für richtige Browser« kann auf mehreren Wegen getroffen werden. Die gängigste Methode ist die Nutzung einer Variablen.

Ihr erstellt zwei SCSS-Dateien – styles.scss und oldie.scss –, in die ihr eure eigentlichen Sass-Dateien (die Partials) importiert. Am Anfang der beiden Dateien definiert ihr eine Variable in zwei Ausprägungen. Im Falle der oldie.scss schreibt ihr isoldIE: true; und im Falle der styles.scss schreibt ihr isoldIE: false.

Aufteilen in Portionen

Die eigentliche Arbeit geschieht dann nicht in diesen beiden eben genannten Dateien, sondern in den Partials. Dabei kann auch einmal eine spezielle oldIE-Datei importiert werden, im Grundsatz sollen aber alle Einzeldateien in die beiden zentralen Dateien importiert werden.

Variablennutzung

Die Variablen entfalten ihre Wirkung in Mixins und in einzelnen Regeln. Sie werden dabei mit @if-Bedingungen in den Code eingeflochten. Dadurch werden die betreffenden Codeteile nur ausgegeben, wenn die Bedingung zutrifft. Ein einfaches Beispiel ist ein Mixin, das oldIE einen Filter zuweist, der dem CSS3-Boxschatten recht nahe kommt:

  1. @mixin box-s($x: 1px, $y: 1px, $offset: 5px, $color: #666) {
  2.     $ie-color: ie-hex-str($color);
  3.  
  4.     @if $isoldIE {
  5.         filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=#{$x}, OffY=#{$y}, Color='#{$ie-color}');    
  6.     } @else {
  7.         box-shadow: $x $y $offset $color;
  8.     }
  9. }

Da nun am Anfang der beiden zentralen Stylesheets die Variable $isoldIE steht, kann dementsprechend dieses Mixin abgearbeitet werden. @if $isoldIE ist gleichbedeutend mit @if $isoldIE == true, sodass der erste Teil des Mixins nur dann ausgegeben wird, wenn es über die Datei oldie.scss aufgerufen wird.

Nicht nur im Mixin

Was im Mixin funktioniert, kann natürlich auch in normalen Regeln angewendet werden. Die Syntax ist einfach zu merken und schnell geschrieben. Da insbesondere ältere IE ein fürchterliches Schriftrendering haben, könnt ihr diesen eine andere Schrift für alle Überschriften zuweisen, als allen anderen Browsern:

  1. #{headings()} {
  2.     @if $isoldIE == false {
  3.         font-family: $font-headline;
  4.         font-weight: 400;      
  5.     }
  6.     @if $isoldIE == true {
  7.         font-family: Verdana, Helvetica, Arial, sans-serif;
  8.         font-weight: normal;
  9.     }
  10. }

Oder ihr schreibt eine Alternative für moderne Selektoren. Irgendwann könnt ihr diesen Teil des Codes dann entfernen, wenn der letzte IE8 endlich den Weg alles Irdischen gegangen ist:

  1. .footerlinks {
  2.     // das folgende Mixin formatiert Links horizontal
  3.     @include inline-list;
  4.     @if $isoldIE == true {
  5.         li {
  6.             border-left: 1px solid #666;
  7.             padding-left: 10px;
  8.             margin-left: 10px;      
  9.             &:first-child {
  10.                 border-left: none;
  11.                 padding-left: 0;
  12.                 margin-left: 0;
  13.             }
  14.         }
  15.     } @else {
  16.         li:not(:first-child) {
  17.             border-left: 1px solid #666;
  18.             padding-left: 10px;
  19.             margin-left: 10px;
  20.         }
  21.     }
  22. }

Fazit

Mit einem Präprozessor wie Sass könnt ihr prima an einer einzelnen Codebasis arbeiten, aber zwei unterschiedliche Varianten ausgeben. So könnt ihr den Schwächen der alten IE entgegenarbeiten, ohne dass moderne Browser mit zusätzlichem Code behelligt werden müssen.

Kommentare

Carsten Hoffmann
am 12.12.2013 - 09:01

Hallo Jens,

schöner Beitrag, er hat aus meiner Sicht nur einen Haken: Zu viel "Liebe" (Aufwand) für die alten Browser. Dann lieber die Bereitschaft zu etwas anderem Aussehen fördern und fordern sowie alles strukturell und vom Design her etwas einfacher halten. In diesem Zusammenhang würde ich dann auch noch diesen schon älteren Artikel von Nicolas Gallagher empfehlen: http://nicolasgallagher.com/mobile-first-css-sass-and-ie/

Lieben Gruß,

Carsten

Permanenter Link

Gunnar Bittersmann
am 12.12.2013 - 10:24

In jenem Artikel ist nichts darüber zu lesen, wie man mit @if-Anweisungen verschiedene Regeln für die Standard- und IE-Stylesheets generieren kann. Gerade das macht aber den Charme des Generierens unterschiedlicher Stylesheets aus einer Quelle aus.

Außerdem gibt der Artikel ein schlechtes Beispiel: an gegenwärtig(!) aktuellen Geräten orientierte in px angegebene Breakpoints. Nicht machen! Besser: am Inhalt orientierte in em angegebene Breakpoints verwenden.

Permanenter Link

Carsten Hoffmann
am 12.12.2013 - 12:25

In jenem Artikel ist nichts darüber zu lesen, wie man mit @if-Anweisungen verschiedene Regeln für die Standard- und IE-Stylesheets generieren kann. Gerade das macht aber den Charme des Generierens unterschiedlicher Stylesheets aus einer Quelle aus.

Das ist ja gerade der Witz und ne Menge weniger Arbeit.

Außerdem gibt der Artikel ein schlechtes Beispiel: an gegenwärtig(!) aktuellen Geräten orientierte in px angegebene Breakpoints. Nicht machen!

Darum ging es mir gar nicht, aber ich stimme beiden verlinkten Argumenten zu.

Permanenter Link

Gunnar Bittersmann
am 12.12.2013 - 10:13

Jahrelang hab ich gepredigt, keine Extrawürste (spezielle Stylesheets) für IEs zu braten, und jetzt das! ;-)

Der Grund gegen getrennte Stylesheets war der erhöhte Wartungsaufwand (und damit verbunden die erhöhte Fehleranfälligkeit). Mit dem Einsatz eines Präprozessors ist dies hinfällig, wenn man aus einer Quelle (SCSS) automatisch die verschiedenen Stylesheets generiert. Single point of change und keine schmutzigen Hacks – the best of both worlds.

Zuerst verlinkt ihr styles.css mit einer Media Query, die den alten IE davon abhält, diese Datei herunterzuladen. Danach verlinkt ihr für oldIE ein spezielles CSS innerhalb eines Conditional Comment.

Das ist prinzipiell keine gute Idee, für Then-Zweig und Else-Zweig völlig verschiedene Techniken zu verwenden. Auch wenn das in diesem Fall gutgehen mag, ist es sauberer, alles mit derselben Technik umzusetzen. Also alles mit Conditional Comments – ja es gibt einen Else-Zweig bei Conditional Comments. TL;DR: So wird’s gemacht.

Getrennte CSS-Dateien für IE7 und IE8 solltet ihr vermeiden, sie würden den Pflegeaufwand unnötig erhöhen.

Nein, wieso? Das ist eine Zeile Conditional Comment und eine einmalig erstellte SCSS-Datei mehr, die genauso aussieht wie die anderen browserspezifischen Dateien: Variable für den UA und @import-Regel – fertig!

Auch hier bietet es sich an, dieselbe Technik für alle Fälle zu nutzen, also konsequent die Verwendung getrennter (aber aus einundderselben Quelle generierter) Stylesheets. Dann kan man auf schmutzige Hacks verzichten.

Nachzulesen ist das auf Folien 27 bis 37 meines Vortrags CSS preprocessors to do the dirty work. TL;DR: Folie 33.

Permanenter Link
Jens Grochtdreis

Jens Grochtdreis (Autor)
am 12.12.2013 - 10:50

Hallo Gunnar, es freut mich, dass mein Ansatz Deine prinzipielle Billigung hat. Dann kann ich ja beruhigt schlafen :-)
Ich verstehe allerdings nicht, was daran schlimm sein soll, zwei unterschiedliche technische Ansätze zu nutzen, um oldIE und moderne Browser voneinander zu trennen. Wo ist jetzt der Vorteil daran, Conditional Comments so zu verbiegen, dass sie vom IE ignoriert werden?

Es geht nur darum, auf der sicheren Seite zu sein, dass das erste CSS niemals den oldIE erreicht. Das schaffe ich prima mit dem kleinen Media Query-Kniff, den ich mir einfach merken kann.

Gegen eine Aufsplittung von IE7 und IE8 mit eigenen Styles bin ich aus ganz pragmatischen Gründen. Ich kann mit simplen Hacks den IE7 vom IE8 trennen. Und der IE7 stirbt demnächst aus, sodass ich nicht noch eine dritte Komplexitätsebenen aufmachen muss: Styles für richtige Browser, Styles für IE8 und IE7, Styles für entweder IE7 oder IE8. DAS wäre in meinen Augen zuviel des Guten.

Ich betreibe den Aufwand nur, weil es ein simples Nebenprodukt der Nutzung eines Präprozessors ist. Und weil ich möchte, dass moderne Browser nicht den Sondercode für oldIE mit geliefert bekommen. Ich sehe es nicht als falsch oder ehrenrührig an, mittels IE-Filtern auch oldIE ein paar CSS3-Techniken zu simulieren. Aber das müssen die CSS3-fähigen Browser ja nicht mitbekommen.

Permanenter Link

Gunnar Bittersmann
am 12.12.2013 - 11:31

Dann kann ich ja beruhigt schlafen

Jetzt?? Ah, du hast bis ins Morgengrauen noch an dem Artikel gearbeitet. ;-)

Es geht nur darum, auf der sicheren Seite zu sein, dass das erste CSS niemals den oldIE erreicht.

Mit Conditional Comments bist du auf der sicheren Seite: Ein auf CC ansprechender IE ist entweder ein 7er (oder darunter), ein 8er oder ein 9er.

Mit verschiedenen Techniken bist du nicht auf der sicheren Seite: Was ist, wenn Microsoft einfallen sollte, ein Update auszurollen, durch den alte IEs auch Media-Queries verstehen? Peng!

Wir beide wissen natürlich, dass die Wahrscheinlichkeit dafür kleiner als ε ist. Deshalb schrieb ich auch „prinzipiell“ und „auch wenn das in diesem Fall gutgehen mag“.

Ich kann mit simplen Hacks den IE7 vom IE8 trennen.

Du kannst auch mit simplen Hacks IE7 und IE8 von Standard-Browsern trennen. Und damit deinen Artikel ad absurdum führen. ;-)

Warum sollte man noch Hacks verwenden, wenn der Präprozessor einem die Möglichkeit gibt, darauf zu verzichten?

sodass ich nicht noch eine dritte Komplexitätsebenen aufmachen muss

Ich sehe nicht, wie sowas wie @if isIE7 or isIE8 anstatt @if $isoldIE die Komplexität großartig erhöhen sollte. Dies gibt einem aber die Möglichkeit bei Bedarf auch @if isIE7 vs. @if isIE8 einzusetzen.

Mit Hacks hingeben würde man eine neue Komplexitätsebene aufmachen – nämlich eine weitere Technik einführen, die man gar nicht mehr braucht.

Und der IE7 stirbt demnächst aus

IE8 leider nicht. Besonders ärgerlich ist, dass der 8er keine CSS-Exprtessions mehr kennt, womit man bis zum 7er noch einige Polyfills im Stylesheet realisieren konnte.

Permanenter Link

hannenz
am 12.12.2013 - 14:35

Ich finde den Ansatz super, gerade weil ich im Moment auch wieder mal dabei bin eine Seite IE8-tauglich zu machen. In einer idealen Welt würde ich auch den Ansatz vertreten, keine Extrawürste für irgendwen zu braten, aber die Welt ist nicht ideal und die Kohle kommt vom Kunden - und der sitzt oft genug noch vor einem IE-Dinosaurier. Wie einer meiner Vorredner schon sagte, ist dieser Ansatz deshalb so schön, weil er das beste aus beiden Welten vereint, ob jetzt die EInbindung mit Media-Query-Hack oder Conditional Comments geschieht ist dann vllt. eher Geschmackssache. (Trotzdem guter Hinweis, dass es bei CC auch ELSE-Zweige gibt; das wusste ich auch noch nicht. BTW, IE11 hat ja Conditional Comments komplett abgeschafft...)

Also ich werde das auf jeden Fall im Moment auf mein laufendes Projekt umsetzen, Danke für den tollen Artikel!

P.S.: Im letzten Code-Beispiel steht im oldIE-Zweig ein :first-child() Selektor. Gibts den nicht erst ab IE9 ??

Permanenter Link
Jens Grochtdreis

Jens Grochtdreis (Autor)
am 12.12.2013 - 15:24

Nein, :first-child gibt es ab IE7. Dummerweise hat das W3C damals nicht daran gedacht, mit :first-child auch :last-child zu vergeben. Das kam dann erst mit CSS3 und diesen Selektor kann dann erst der IE9. Deshalb kannst Du versuchen, bei Einsatz von :last-child einfach andrersherum zu denken, dann klappt es auch mit oldIE.

Permanenter Link

Christian Rauni...
am 14.01.2014 - 23:04

Früher habe ich das für die oldIEs auch einfach umgedreht aber ich habe aufgehört mir über :first-child und :last-child Gedanken zu machen. Die oldIE user bekommen bei mir einfach http://selectivizr.com/ vorgesetzt und gut ist. Da ist dann gleich :nth-child(n) inklusive und ich habe weniger Kopfschmerzen =)

Permanenter Link

Sascha Fuchs
am 14.12.2013 - 16:43

Ich halte den Ansatz für Sinnvoll, wer z.B. nach Performance First arbeitet wird sein CSS am Ende auch auf spliten um mobile Browser nicht unnötig zu belasten, während Desktop das volle Programm bekommt (auf einem Smartphone braucht man in der Regel kaum noch ein Gridsystem). Und genauso verhält es sich mit IE8.

Ich persönlich gehe nicht mehr her und mach den IE8 mit Polyfills auch noch responsive (das war vor Jahren mal die toll selbst IE6 responsive zu bekommen), und da macht es ebenso sinn zu spliten.

So bekommt der IE8 eben sein eigenes CSS File das ist nicht responsive und an seine möglichkeiten Angepasst, moderne Browser bekommen wesentlich mehr.

Um das Spliten zu vereinfachen kann man eine Compass Extension verwenden https://github.com/Team-Sass/jacket.

Permanenter Link
Jens Grochtdreis

Jens Grochtdreis (Autor)
am 15.12.2013 - 12:59

Den IE8 habe ich noch nie mittels JS responsive gemacht. Ich halte das für Quatsch, weil es keinen Usecase dafür gibt. Auf mobilen Endgeräten gibt es nur Browser, keinen IE8.

Das Gridsystem für mobile zu ersparen ist aber auch des Guten zuviel. Wenn man ein kluges Gridsystem nutzt, dann sind es nachher 12 oder 16 Regeln, nicht mehr. Das trägt nicht negativ auf. Da spart man mehr, wenn man sich gründlich um Bilderkompression kümmert.

Die Compass-Extension kannte ich noch nicht. Aber ich wüßte jetzt auch nicht, warum ich zum Aufsplitten Hilfe benötige. Ich schaue sie mir mal an, vielleicht weiss ich es dann.

Permanenter Link

hannenz
am 19.12.2013 - 11:15

Kann es sein, dass der media="all and (min-width:0px) gar nicht funktioniert?! Soweit ich das sehe lädt IE8 das Stylesheet und wendet die Regeln auch an. Kann das jemand bestätigen oder dementieren? Vielleicht mach ich ja auch was falsch oder hab ich was übersehen...

Permanenter Link
Jens Grochtdreis

Jens Grochtdreis (Autor)
am 19.12.2013 - 11:32

Ich habe Dir mal eine einfache Testseite aufgesetzt. Du wirst sehen, dass Du im IE8 nur eine Überschrift zu Gesicht bekommen wirst, während Du in modernen Browsern zwei Überschriften sehen wirst.

Permanenter Link

hannenz
am 19.12.2013 - 13:40

Stimmt, es funktioniert; es ist nur verwirrend, das in den Entwicklertools im IE8 das Stylesheet angezeit wird und auch die Regeln, es sieht also so aus, als würden sie angewendet Danke für die rasche Aufklärung :)

Permanenter Link

Christian Rauni...
am 14.01.2014 - 23:15

Tolle Methode, Sven Wolfermann hat einen ähnlichen Artikel verfasst: http://maddesigns.de/mobile-first-ie8-fallback-sass-2008.html

Ich würde sogar soweit gehen und die Anweisung in ein @mixin mit @content abstrahieren, da is man dann sogar etwas flexiber was den Inhalt angeht. Das fühlt sich dann auch ähnlich wie .oldie & {}

@include oldie {
    background: red;
}

Macht nur dann Sinn, wenn man kein @else braucht und nur überschreiben will, aber für kleine Fixes ausreichend.

Permanenter Link

Peter Hadorn
am 15.03.2014 - 14:41

Guter Artikel, wir benutzen die gleiche Methode für IE7/8. Für Entwickler die gerne mit REM arbeiten ist dieser Ansatz sehr empfehlenswert, um im CSS der alten IE's automatisch px auszugeben: http://davidwalsh.name/rem-px-browser-function-sass

Permanenter Link

Die Kommentare sind geschlossen.