Less im Visual Studio

Less Logo

Weniger ist oft mehr. Das gilt für immer mehr Bereiche der Entwicklung. Warum? Weil wir so schon genug zu tun haben und vor allem eines wollen: Weniger Kram, den wir im Auge behalten müssen. less versucht hier, einen weiteren Baustein beizusteuern, indem es uns ein paar lieb gewonnene Features aus der Programmierung in CSS beschert.

Screencast

Für die Hastigen hier wieder das Video zum Artikel:

Vorbemerkungen

In diesem Artikel werde ich einen Rundflug über die Möglichkeiten, die less und bieten kann durchzuführen. Natürlich konzentriere ich mich auch hier wieder auf die Nutzung im Visual Studio. Als Einstieg in das Thema bietet sich zunächst einmal die Seite lesscss.org. an. Die gibt’s zwar auch in Deutsch, so richtig nett liest sich das allerdings nicht. less selbst wurde ursprünglich von Alexis Seller entwickelt und wird auf github bereit gestellt. Die Entwicklung scheint relativ busy zu sein und somit kann man sich auch hier auf regelmäßige Updates freuen.

Beschäftift man sich als Neuling das erste mal mit less, wird man mal wieder gleich bei der Erklärung zu less mit neuen Fremdworten zugeschüttet:

LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions.

Aha! Vielen Dank erstmal dafür, aber was sind eigentlich „mixins“ und was macht ein Verhalten „dynamic“? (Grundsätzliche Fragen, wie z.B. ein passives Verhalten aussehen könnte, sollten an dieser Stelle vorerst ausgelagert werden :-)).

Diese Begriffe will ich zunächst mal versuchen zu klären.

Mixin

Ich selbst habe mich relativ lange schwer getan mit dem Verständnis der Mixins. Rückblickend betrachtet vor allem, weil sie so simpel sind. Als Programmierer kennt man das Konzept dahinter ohnehin: Wiederverwendung.

Ein Mixin entsteht, wenn man eine CSS-Klasse in einer anderen CSS-Anweisung verwendet. Ein Beispiel vereinfacht das Verständnis an dieser Stelle bestimmt:

.mixinClass {
    background-color: #e0e0e0;
}

#someElement {
    .mixinClass;
}

Das ist schon mal neu und der Sinn erschließt sich gestandenen Web-Programmierern sofort. Ich brauche alle Anweisungen innerhalb der Klasse mixinClass nicht ständig neu zu definieren und mülle mich weniger zu. Das allein würde aber nicht reichen. Dazu ein kleines Beispiel:

.mixinClass {
    background: url('../images/sample01.png') no-repeat;
}

#someElement {
    .mixinClass;
}

#someOtherElement {
    .mixinClass;
}

Was ist hier das Problem? Sieht doch gut aus! Das Problem ist, dass die mixinClass immer das gleiche Image verwendet, wir aber vielleicht bei someOtherElement ein anderes Bild verwenden wollen.

Um sowas abzubilden, wurden die Mixins „aufgeschlaut“. Sie sind nicht einfach nur ein anderes Wort für CSS-Klasse, sondern sie sind in Wahrheit Methoden. Das mixinClass-Element aus Listing 2 sieht nämlich eigentlich so aus:

.mixinClass() {
    background: url('../images/sample01.png') no-repeat;
}

Wer den Unterschied nicht gleich erkennt: Die runden Klammern nach dem Namen des Mixins. Und wer jetzt gerate hat, dass in die Klammern etwas wie Parameter rein darf, der hat Recht. Hier ein Beispiel:

.mixinClass(@imageName) {
    background: url(@imageName) no-repeat;
}
#someElement {
    .mixinClass('../images/sample01.png');
}

(Wer sich für optionale Parameter interessiert, sei auf Listing 9 verwiesen.)

Listing 4 zeigt auch gleich die neue Verwendung des Mixins und ein neues Element von less: Variablen.

Variablen

Eine Variable in less beginnt immer mit einem „@“. Der Zuweisungs-Operator in less ist „:“. Die folgende Zeile ist in less also vollkommen valide:

@defaultBackground: #e0e0e0;

Verwendet werden kann sie ab jetzt an jeder beliebigen Stelle. Es spielt keine Rolle, wo in einer .less-Datei die Definition von Variablen und Mixins erfolgt. Definiert man die Variable z.B. in einer Zeile 100, kann man sie in Zeile 20 verwenden.

Funktionen

Unser Beispiel aus Listing 4 könnte man sich nun auch etwas komfortabler vorstellen:

@basePath: '../images/';
.mixinClass(@imageName) {
    background: url(@imageName) no-repeat;
}

Unser Beispiel aus Listing 4 könnte man sich nun auch etwas komfortabler vorstellen:

@basePath: '../images/';
.mixinClass(@basePath@imageName) {
    background: url(@imageName) no-repeat;
}

Wer das ausführt, wird eher enttäuscht sein. Damit man Variablen so verwenden kann, muss man den Listing 7 anpassen:

@basePath: '../images/';
.mixinClass(@imageName) {
    background: url('@{basePath}@{imageName}') no-repeat;
}
#someElement {
    .mixinClass('sample01.png');
}

Operatoren

Was less nun vollends abrundet, ist die Tatsache, dass Operatoren unterstützt werden. Listing 9 zeigt vollends validen less-Code:

.mixinClass(@imageName, @offset:2) {
    background: url('@{basePath}@{imageName}') no-repeat;
    margin-left: @offset * 10px;
}

In Zeile 3 wird der Wert ’10px‘ mit dem übergebenen offset multipliziert. Ja, less nimmt „px“ raus, multipliziert mit dem offset und hängt „px“ dann wieder an das Ergebnis an.

Less einbinden

Für alle diejenigen unter den codingfreaks-Lesern, die ohnehin Visual Studio verwenden wollen, sei der Hinweis auf den unteren Abschnitt WebEssentials erlaubt.

Wer bis hierher gekommen ist, hat sich garantiert schon gefragt, was er denn nun tun muss, damit das ganze auch wirklich läuft. Die Antwort liegt in 2 Schritten:

  1. Es wird ein Stylesheet-Verweis auf die .less-Datei erzeugt.
  2. Es wird less.js eingebunden.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>less-Test</title>
        <link rel="stylesheet/less" type="text/css" href="test.less"/>
        <script src="less.js" type="text/javascript"></script>
    </head>
    <body>
        <div id="someElement"></div>
    </body>
</html>

Die less.js bekommt man von der oben erwähnten less-Seite. Sie benötigt keine vorherige jQuery-Einbindung. Wichtig ist nur, dass das less-Styleshett unbedingt vor dem less.js referenziert wird.

Ein Visual Studio-Minimal-Projekt sieht also im Solution Explorer ca. so aus:

Abb. 1: Minimales less im VS
Abb. 1: Minimales less im VS

Läuft nicht im VS!

Das erste mal F5 im Visual Studio ist nun eher enttäuschend. Es kommen Fehler, die besagen, dass er die test.less-Datei nicht laden kann. Der Grund ist, dass ein Standard-IIS-Express nicht weiß, was er mit .less-Dateien machen soll. Bringen wir es ihm also bei und das am besten in der web.config unseres Projektes:

<?xml version="1.0"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".less" mimeType="text/css" />
        </staticContent>
    </system.webServer>
</configuration>

Die Zeilen 3-6 habe ich nur der Vollständigkeit mit drin gelassen. Entscheidend ist der komplette Inhalt von <system.webServer>. Hier teilen wir unserem Ziel-IIS mit, was wir als Ausnahme vom Standard definiert haben wollen – in diesem Fall halt einen neuen MIME-Typ. Wir teilen dem IIS damit mit, dass wir alles was auf .less endet gern als CSS angesehen wissen möchten.

Nach dieser Änderung läuft unsere simple Anwendung, wenn die index.html, wie in Listing 10 gestaltet wurde:

Abb. 2: Seite im Browser
Abb. 2: Seite im Browser

Wie sieht denn nun aber unser CSS aus? Ein Blick in den Firebug hilft schnell weiter:

Abb. 3: Ergebnis-CSS

Abb. 3: Ergebnis-CSS

Und hier noch das dazu gehörige less:

@defaultBackground: #e0e0e0;
@basePath: '../images/';
.mixinClass(@imageName, @offset:2) {
    background: url('@{basePath}@{imageName}') no-repeat;
    margin-left: @offset * 10px;
    width: 199px;
    height: 81px;
}
#someElement {
    .mixinClass('sample01.png');
}

Die defaultBackground-Variable benutze ich zwar nicht, habe sie aber der Vollständigkeit halber mal drin gelassen.

Bis hierhin könnten böse Zungen nun behaupten, dass wir so ziemlich verloren haben durch less. Nix less, eher more, oder was?

Dieser Eindruck würde nur dann entstehen, wenn man nicht weiter denkt. Das Beispiel ist bisher noch sehr einfach. Erweitern wir es doch ein wenig:

@defaultBackground: #e0e0e0;
@basePath: '../images/';
body {
    background: @defaultBackground;
}
.mixinClass(@imageName, @offset:2) {
    background: url('@{basePath}@{imageName}') no-repeat;
    margin-left: @offset * 10px;
    color: @defaultBackground;
    width: 199px;
    height: 81px;
}
#someElement {
    .mixinClass('sample01.png');
}
#someElement2 {
    .mixinClass('sample02.png');
}
#someElement3 {
    .mixinClass('sample03.jpg');
}

Mit ein wenig angepassten HTML in index.html würde das Ergebnis im CSS schon anders aussehen:

body {
    background: #e0e0e0;
}
#someElement {
    background: url('../images/sample01.png') no-repeat;
    margin-left: 20px;
    color: #e0e0e0;
    width: 199px;
    height: 81px;
}
#someElement2 {
    background: url('../images/sample02.png') no-repeat;
    margin-left: 20px;
    color: #e0e0e0;
    width: 199px;
    height: 81px;
}
#someElement3 {
    background: url('../images/sample03.jpg') no-repeat;
    margin-left: 20px;
    color: #e0e0e0;
    width: 199px;
    height: 81px;
}

24 Zeilen CSS wurden erzeugt mit 21 Zeilen less. Mit anderen Worten: Je mehr wir von nun beginnen, Definitionen innerhalb von less wieder zu verwenden, desto eher rechnet sich die Beschäftigung mit der neuen Technik.

Und noch mehr!

Mit dem bis hierher gezeigten haben wir gerade mal an der Oberfläche von less gekrazt. Ein Blick auf die less-Referenz macht schnell klar, welches Potential in der Idee und dem OpenSource-Konzept steckt. Wir könnten z.B. den mixinClass-Parameter offset leicht abrunden:

margin-left: floor(@offset) * 10px;

less ist außerdem so sehr eine kleine Programmiersprache, dass auch weiterführende Themen bereits bedacht sind. Dazu gehören

Gleichzeitig ist less so sehr CSS, dass daraus wiederum folgendes übernommen wurde:

Ein paar Bemerkungen sind bei all dem Komfort aber angebracht. Namespaces verhalten sich nicht analog zu logischen Containern. Das Namespace-Konzept basiert auf #-Handlern und ist daher nicht einfach so als Struktur einzubinden, sondern erfordert auch Anpassungen im HTML-Gerüst.

Ziemlich cool gelungen dagegen ist die Umsetzung von @import. Es erlaubt es uns, die Definition von less auf mehrere Dateien aufzusplitten. Hier ein Beispiel.

Zunächst füge ich meinem Projekt eine neue „variables.less“ hinzu und übertrage alle Variablen-Deklarationen aus test.less dort hinein:

@defaultBackground: color('red');
@basePath: '../images/';

Dann füge ich in test.less das @import-once ein (sorgt im Gegensatz zu @import für das auf jeden Fall nur einmalige Einbinden):

@import-once 'variables.less';
/* und der Rest ... */

Das war’s auch schon. Die Variablen sind nun fein säuberlich in einer anderen Datei und können einfacher gepflegt werden.

less.js

less ist mehr, als nur ein „dummer“ Interpreter und Code-Converter. Über eingebaute JavaScript-Funktionen kann das Verhalten von less überall angepasst werden und wir können in unserem eigenen JavaScript less nutzen.

Wir könnten z.B. dafür sorgen, dass bei Klick auf das erste div die @defaultBackground-Variable verändert wird:


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>less-Test</title>
        <link rel="stylesheet/less" type="text/css" href="test.less"/>
        <script src="less.js" type="text/javascript"></script>
        <script type="text/javascript">
            function ChangeColor() {
                less.modifyVars({
                    '@defaultBackground': '#5B83AD'
                });
            }
        </script>
    </head>
    <body>
        <div id="someElement" onclick="ChangeColor();"></div>
        <div id="someElement2"></div>
        <div id="someElement3"></div>
    </body>
</html>

ChangeColor ändert also während der Laufzeit die in der less-Datei definierte Farbe. Das beste von all dem ist aber, dass die Änderung sofort sichtbar wird. Das liegt daran, dass less.js diese Änderungen im Auge behält und automatisch synchronisiert – komplett auf dem Client ohne request! Wer dieses Verhalten (und anderes) steuern möchte, kann dies ohne weiteres tun (siehe Startup-Konfiguration).

less auf dem Server

Seit node.js immer populärer wird, fragen anscheinend immer mehr Leute anch serverseitigem JS. Auch less steht dem in nichts nach und kann komplett auf dem Server ausgeführt werden. Da ich selbst C# programmieren kann und angesichts meines Blog-Logos werde ich auf dieses Detail nicht weiter eingehen. Es geht halt!

less und Visual Studio

Für uns VS-Nutzer kann all das bisher Gesagte sogar noch einfacher wahr werden. Für die grundsätzlichen Konvertierungen und Funktionen reicht einem VS-Nutzer die Installation und das Erweitern mit den Web Essentials.

Hat man diese beiden Vorbedingungen  erfüllt, tauchen Less-Stylesheets als eigenes Element im Add-New-Item-Dialog auf:

Abb. 4: Less-Element
Abb. 4: Less-Element

Damit nicht genug. Der Editor für diese Datei bringt eine Überraschung. Hier ein Screenshot der test.less:

Abb. 5: Less-Editor im VS

Abb. 5: Less-Editor im VS

Auf der linken Seite kann man sein less eingeben und wie durch Magie erscheint im rechten Bereich das Ergebnis-CSS. Dieses findet sich in Roh- und Minified-Form unterhalb der less-Datei wieder:

Abb. 6: CSS-Ergebnisse mit im Projekt
Abb. 6: CSS-Ergebnisse mit im Projekt

Das führt nun dazu, dass wir less einfach nicht mehr in unsere HTML-Seiten einbinden müssen. Es ist ja ohnehin etwas für uns Entwickler und taucht auf dem Client eigentlich nicht auf. Was wir eigentlich wollen, ist einfach zu wartendes CSS und gewartet wird im Visual Studio. Es reicht nun völlig aus, die *.css-Dateien wie immer zu referenzieren.

Wollen wir die oben beschriebenen Programmier-Features nutzen, müssen wir natürlich wieder less einbinden!

Fazit

Ich habe eine Weile gebraucht, bis ich das Konzept so einigermaßen verstanden und akzeptiert hatte und möchte dies natürlich auch jedem anderen zugestehen. Es gibt aber überhaupt keinen Grund, misstrauisch zu sein und mit Web Essentials auch keinerlei Entschuldigung, es nicht zu nutzen. Die grundsätzliche Idee von less und seinen Tools findet vermehrt Einzug in die Developer-Welt und diesmal bin nicht mal ich dagegen. Typescript geht beispielsweise einen ähnlichen Ansatz.

Wer übrigens less einfach mal ausprobieren möchte, sollte einmal einen Blick auf den Less2Css werfen.

2 Replies to “Less im Visual Studio”

  1. Hallo sprinter,

    Vielen Dank für den sehr gelungenen Artikel zum Thema less. Vor allem der letzte Teil mit Web Essentials und „fertigen“ CSS Dateien gefällt mir sehr.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.