Freigeben über


Innovation

Programmieren von CSS: Effizienterer Code mit LESS

Dino Esposito

Dino EspositoIn diesem Artikel erläutere ich, wie Sie das LESS-Framework bei der Webentwicklung verwenden können, um dynamisch CSS-Inhalte zu generieren.

CSS mit seinem – größtenteils erfüllten – Versprechen der vollständigen Trennung von Inhalten und Darstellung von Webseiten war zweifellos ein großer Fortschritt. CSS gehört zwar zum Gebiet der Designer (oder sollte dazu gehören?), aber das Prinzip der Trennung der Bereiche wird von fast allen Entwicklern berücksichtigt. CSS verbreitete sich daher rasch und ist in der Webentwicklung fest verankert, bis hin zu dem Punkt, dass CSS manchmal Mühe hat, mit modernen Websites mitzuhalten.

Es ist nicht so, dass CSS zum Formatieren moderner, grafisch umfassender und ansprechender Websites unzureichend ist. Aber eine rein deklarative Sprache ist nicht immer geeignet, um komplexe und miteinander verknüpfte Deklarationen von Formatvorlagen auszudrücken. Zum Glück können Browser beliebigen CSS-Code interpretieren, solange dieser korrekt geschrieben ist, aber gilt dasselbe auch für uns?

Eine relativ neue Richtung in der Webentwicklung zielt darauf ab, eine Infrastruktur um CSS herum zu erstellen, sodass Entwickler und Designer denselben CSS-Code nachhaltiger erzeugen können. Das resultierende Stylesheet für den Browser ist dasselbe, aber es soll auf andere Weise entwickelt werden, leichter lesbar und besser zu verwalten sein.

Dieser Webentwicklungsbereich nahm vor wenigen Jahren seinen Anfang und ist nun soweit gereift, dass mehrere Frameworks verfügbar sind, um Sie bei der Generierung von dynamischen CSS-Inhalten zu unterstützen. Ich stelle eines dieser Frameworks – das LESS-Framework – in einer Zusammenfassung dar, und ich zeige Ihnen, wie es in ASP.NET MVC-Lösungen integriert werden kann.

Warum LESS?

Eines der größten Probleme, die die Entwickler mit LESS lösen möchten, ist die Wiederholung von Informationen. Als Softwareentwickler kennen Sie wahrscheinlich das Wiederhole-dich-nicht-Prinzip (Don't Repeat Yourself, DRY) und wenden es täglich an. Der Hauptvorteil von DRY ist, dass dieselben Informationen an weniger Stellen vorgehalten und damit an weniger Stellen aktualisiert werden müssen.

In reinem CSS gibt es einfach keine DRY-Probleme. Ein Beispiel: Wenn in einigen anderen Szenarios eine Farbe in mehreren Klassen verwendet wird und Sie sie ändern müssen, können Sie wahrscheinlich nur so vorgehen, dass Sie die Farbe für jedes einzelne Auftreten aktualisieren. Mit CSS-Klassen können Sie die Darstellung bestimmter Elemente definieren und diese seitenübergreifend auf dieselbe Weise für formatbezogene Elemente wiederverwenden. CSS-Klassen reduzieren definitiv Wiederholungen. Bei anderen Aspekten reichen sie jedoch manchmal nicht aus.

Ein Problem bei CSS-Klassen ist, dass sie auf der Ebene des semantischen HTML-Elements funktionieren. Beim Erstellen verschiedener CSS-Klassen begegnen uns häufig Wiederholungen von kleinen Details wie Angaben zur Farbe oder Breite. Es ist schwierig, eine Klasse für jedes dieser wiederholbaren Details zu haben. Sogar wenn es Ihnen gelingt, für fast jede wiederholbare Formatvorlage, wie Farben und Breiten, eine CSS-Klasse zu verwenden, müssen Sie bei der Formatierung semantischer Elemente wie beispielsweise einem Container mehrere CSS-Klassen miteinander verketten, um den gewünschten Effekt zu erreichen.

Wenn Sie schon einmal eine Webseite mithilfe eines Frameworks wie Bootstrap entworfen haben, wissen Sie, wovon ich rede. Im Folgenden finden Sie ein Beispiel:

<a class="btn btn-primary" ... />

Zunächst wird der Anker als Schaltfläche definiert (btn-Klasse), und dann wird eine bestimmte Sorte von Schaltfläche festgelegt (btn-primary-Klasse). Dieser Ansatz funktioniert, kann aber möglicherweise viel Arbeit erfordern, um für die benötigten Klassen vorauszuplanen. Er verursacht Aufwand in Webprojekten, die oft kurz vor Abgabeterminen stehen.

Eine dynamische Stylesheetsprache wie LESS bedeutet eine unorthodoxe Herangehensweise. Sie verwenden keine Zeit darauf, den reinen CSS-Code intelligenter zu machen. Sie verwenden einfach andere Tools – meistens Sprachen –, um ihn zu generieren. LESS ist daher ein Framework, das CSS um programmiererfreundliche Konzepte ergänzt, beispielsweise Variablen, Blöcke und Funktionen.

Eng mit der dynamischen CSS-Generierung verbunden ist das Problem, diesen Code zu reinem CSS zu verarbeiten, das der Browser nutzen kann. Der Client kann den LESS-Code über Ad-hoc-JavaScript-Code verarbeiten oder auf dem Server vorverarbeiten, sodass der Browser nur das endgültige CSS empfängt.

Einrichten von LESS in ASP.NET MVC

Ich möchte Ihnen zeigen, wie Sie LESS in einer ASP.NET MVC-Anwendung verwenden können. Als Erstes widme ich mich der clientseitigen Verarbeitung des LESS-Codes. Fügen Sie folgenden Code in den HEAD-Abschnitt der Layoutdatei ein:

<link rel="stylesheet/less"
  type="text/css"
 href="@Url.Content("~/content/less/mysite.less")" />
<script type="text/javascript"
 src="@Url.Content("~/content/scripts/less-1.3.3.min.js")"></script>

Hierbei wird vorausgesetzt, dass Sie im Projekt einen Ordner „Content/Less“ erstellt haben, der die gesamten LESS-Dateien enthalten soll. Für die eigentliche LESS-zu-CSS-Verarbeitung im Browser ist eine JavaScript-Datei erforderlich. Diese Skriptdatei erhalten Sie auf lesscss.org. Ich möchte auf einige Szenarios eingehen, in denen LESS von Vorteil ist.

LESS in Aktion: Variablen

Die Rolle von LESS-Variablen wird verständlich, wenn wir CSS-Farbverläufe betrachten. Jahrelang haben die Designer kleine GIF-Dateien verwendet, um den Hintergrund von HTML-Containern mit Farbverläufen zu versehen. In jüngerer Zeit haben die Browser CSS-Unterstützung für Farbverläufe hinzugefügt. Diese Farbverläufe sind durch die lineare Farbverlaufssyntax und deren Variationen auch Bestandteil des offiziellen CSS3-Standards. Wenn Sie sicherstellen möchten, dass eine möglichst große Bandbreite an Browsern den Farbverlauf übernimmt, müssen Sie aber leider auf solchen Code wie in Abbildung 1 zurückgreifen.

Der Code in Abbildung 1 ist fast unlesbar. Noch schlimmer ist, dass er überall dort wiederholt werden muss, wo Sie diesen Farbverlauf haben möchten. Und wenn Sie die Farbe des Farbverlaufs (oder einfach die Sättigung oder Überblendung) leicht verändern möchten, besteht die einzige Möglichkeit darin, jedes Auftreten manuell zu ändern. Es liegt klar auf der Hand, dass dies äußerst mühsam sein kann, aber in reinem CSS funktioniert es nur auf diese Weise.

Abbildung 1: Umfassender Code, mit dem Farbverläufe in zahlreichen Browsern angezeigt werden

/* Old browsers fallback */
background-color: #ff0000;
background: url(images/red_gradient.png);
background-repeat: repeat-x;
/* Browser specific syntax */
background: -moz-linear-gradient(  left,  #fceabb 0%, 
  #fccd4d 50%, #f8b500 51%, #fbdf93 100%);
background: -Webkit-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
background: -o-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
background: -ms-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
/* Standard syntax */
background: linear-gradient(  to right, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);

Eine bessere Lösung für Farbverläufe finden Sie außerhalb von CSS im LESS-Framework. In LESS definieren Sie das CSS für den Farbverlauf einmal, und um darauf zu verweisen, verwenden Sie dann an den geeigneten Stellen den Namen. Im Folgenden finden Sie ein Beispiel:

.background-gradient-orange { background: #fceabb; ... }
.container { .background-gradient-orange; }

Die background-gradient-orange-Klasse wird durch den Namen in die container-Klasse und ggf. jede beliebige andere Klasse eingebettet. Die Definition des Farbverlaufs bleibt dabei an einem Ort.

Aus Entwicklersicht ist daran nichts Revolutionäres. Allerdings wird ein Feature verwendet, das es in CSS nicht gibt: Variablen. Tatsächlich funktioniert die vorstehende Syntax nicht, wenn Sie die Datei als ein reines Stylesheet speichern und dies referenzieren. Es ist etwas Code erforderlich, um die erweiterte Syntax in reines CSS umzuwandeln. Der LESS-JavaScript-Parser führt genau das aus und erweitert Variablen auf ihre eigentlichen CSS-Inhalte.

Variablen gelten auch für skalare Werte wie Farben oder Größen. Betrachten Sie den folgenden LESS-Code:

@black: #111;
#main {  color: @black; }
.header { background-color: @black; }

Der Parser erweitert die @black-Variable auf den zugeordneten Wert und ersetzt sie in der gesamten Datei. Das Endergebnis ist, dass Sie die Farbe an einer Stelle verändern und sich diese Änderung automatisch durch die Datei hindurchzieht.

LESS in Aktion: Importe

Bei Bedarf können Sie den LESS-Code auf mehrere Dateien, Verweisdateien und enthaltene Klassen aufteilen. Angenommen, Sie erstellen eine Datei „gradients.less“ mit folgendem Inhalt:

.background-gradient-orange { background: #fceabb; ... }

In einer weiteren LESS-Datei, zum Beispiel „main.less“, können Sie durch Importieren der Datei auf beliebige Farbverläufe verweisen:

@import "gradients";
.container { .background-gradient-orange; }

Wenn sich „gradients.less“ (die Erweiterung ist nicht unbedingt erforderlich) in einem anderen Ordner befindet, müssen Sie im Aufruf zum Importieren einen Pfad angeben.

LESS-Mixins

Ich habe das LESS-Artefakt für Farbverläufe als Variable bezeichnet. Das ist genau genommen nicht ganz korrekt. In LESS umfasst eine Variable einen einzelnen Wert. Ein Container für eine CSS-Klasse wird als Mixin bezeichnet. Ein Mixin ist einer Funktion ähnlich, enthält jedoch keine benutzerdefinierte Logik. Genau wie eine Funktion kann ein LESS-Mixin über Parameter verfügen und diese verarbeiten. Der Code in Abbildung 2 zeigt ein Mixin.

Das shadow-Mixin in Abbildung 2 definiert die Formatvorlagen für einen Feldschatten und macht die Farbe als externen Parameter verfügbar. Entsprechend definiert das text-box-Mixin die grundlegende Darstellung eines Eingabefelds. Es importiert die Schattendefinition und behält den Parameter für die Breite bei. So wird das Definieren von drei Klassen für Eingabefelder in verschiedenen Größen („mini“, „normal“ und „large“) zum Kinderspiel. Und was noch wichtiger ist, es ist nur ein Bruchteil der Bearbeitung erforderlich, und Aktualisierungen können mit minimalem Aufwand ausgeführt werden (siehe Abbildung 3).

Abbildung 2: Mixins im LESS-Framework

/*  Mixins  */
.shadow(@color) {
  box-shadow: 3px 3px 2px @color;
}
.text-box(@width) {
  .shadow(#555);
  border: solid 1px #000;
  background-color: #dddd00;
  padding: 2px;
  width: @width;
}
/*  CSS classes  */
.text-box-mini {
  .text-box(50px);
}
.text-box-normal {
  .text-box(100px);
}
.text-box-large {
  .text-box(200px);
}

LESS Mixins in Action
Abbildung 3: LESS-Mixins in Aktion

Mixins können mehrere Parameter und auch eine variable Anzahl von Parametern akzeptieren. Außerdem können einzelne Parameter Standardwerte unterstützen:

.mixin(@color: #ff0) { ... }

LESS ist kein Ausdruck einer umfassenden Programmiersprache und enthält vom Entwurf her keine Befehle, um Bedingungen oder Schleifen anzugeben. Allerdings kann das Verhalten von einem Mixin je nach übergebenem Wert verschieden sein. Angenommen, Sie möchten eine größere Schaltfläche mit einem breiteren Rand und einer fetteren Schriftart versehen. Sie definieren ein parametrisches Mixin mit Namen „button“, und Sie binden mithilfe des Schlüsselworts „when“ Einstellungen an eine Bedingung. Die Bedingung muss auf einem einzelnen Parameter basieren:

.button (@size) when (@size < 100px) {
 padding: 3px;
 font-size: 0.7em;
 width: @size *2;
}
.button (@size) when (@size >= 100px) {
  padding: 10px;
  font-size: 1.0em;
  font-weight: 700;
  background-color: red;
  width: @size *3;
}

Sie wenden unterschiedliche Einstellungen an, aber Sie können auch grundlegende Vorgänge nutzen, um die Größe mit einem Faktor zu multiplizieren. Verwenden Sie als Nächstes Mixins in CSS-Klassen:

.push-button-large {
  .button(150px);
}
.push-button-small {
  .button(80px);
}

Abbildung 4 zeigt die Ergebnisse der Ausführung dieses Codes.

Effects of Using LESS Mixins in CSS Classes
Abbildung 4: Auswirkungen von LESS-Mixins in CSS-Klassen

LESS bietet eine große Anzahl von vordefinierten Funktionen zum Bearbeiten von Farben. Es gibt Funktionen, mit denen Sie Farben prozentual abdunkeln, aufhellen oder sättigen können, oder mit denen Sie sie wie hier gezeigt prozentual ein- und ausblenden können:

.push-button {
  background-color: fade(red, 30%);
}

Eine vollständige Dokumentation der von LESS unterstützten Funktionen finden Sie unter lesscss.org.

Verschachteln von Klassen

Ich finde es ziemlich ärgerlich, CSS-Blocks wiederholen zu müssen, um gleichgeordnete Formatvorlagen anzugeben. Hier ein typisches Beispiel:

#container h1 { ... }
#container p { ... }
#container p a { ... }
#container img { ... }

In gut geschriebenem reinem CSS können Sie tatsächlich viele Wiederholungen vermeiden. Aber die Art, wie die Formatvorlagen angeordnet sind – normalerweise eine einfache Liste – kann verbessert werden. In diesem Fall ist ein wenig Hierarchie wünschenswert. In LESS können Sie Stilregeln folgendermaßen verschachteln:

.container {
  h1 {
    font-size: 0.8em;
   color: fade(#333, 30%);
   a {
     color: #345;
     &:hover {color: red;}
    }
  }
}

Wenn er verarbeitet wurde, erzeugt der vorhergehende LESS-Code die folgenden Formatvorlagen:

.container h1
.container h1 a
.container h1a:hover

Serverseitige Verarbeitung

Sie können den LESS-Code unverändert herunterladen und auf dem Client über JavaScript-Code verarbeiten. Sie können den Code auch auf dem Server vorverarbeiten und als reines CSS auf den Client herunterladen. Im ersten Fall funktioniert alles so, als ob Sie reine CSS-Dateien verwenden würden: Serverseitige Änderungen werden bei der nächsten Seitenaktualisierung auf den Client angewendet.

Wenn die Leistung für Sie von Bedeutung ist und Sie mit umfangreichen, komplexen CSS-Dateien arbeiten, kann die serverseitige Vorverarbeitung eine bessere Option sein. Die serverseitige Vorverarbeitung findet jedes Mal statt, wenn Sie das CSS auf dem Server ändern. Sie können den zusätzlichen Schritt am Ende vom Buildprozess manuell einfügen. Die Vorverarbeitung von LESS-Code zu CSS führen Sie mit dem LESS-Compiler über die Befehlszeile aus. Der Compiler ist Bestandteil des Dotless-NuGet-Pakets, das Sie für serverseitige Aufgaben installieren.

In ASP.NET MVC 4 können Sie allerdings das LESS-Framework in den Bündelungsmechanismus integrieren, über den ich in meinem Artikel vom Oktober 2013 „Programmieren von CSS: Bündelung und Minimierung“ (msdn.microsoft.com/magazine/dn451436) geschrieben habe. Damit stellen Sie sicher, dass die Transformation von LESS zu CSS jedes Mal ausgeführt wird, wenn Sie eine LESS-Datei anfordern. Außerdem wird mit dem If-Modified-Since-Header die ordnungsgemäße Verwaltung der Zwischenspeicherung gewährleistet. Zudem können Sie Parsen und Minimieren kombinieren. Um LESS in ASP.NET MVC zu integrieren, laden Sie zuerst das Dotless-NuGet-Paket herunter, und installieren Sie es. Anschließend fügen Sie der BundleConfig-Klasse den folgenden Code hinzu:

var lessBundle =
  new Bundle("~/myless").IncludeDirectory("~/content/less", "*.less");
lessBundle.Transforms.Add(new LessTransform());
lessBundle.Transforms.Add(new CssMinify());
bundles.Add(lessBundle);

Das Bündel packt alle LESS-Dateien, die im angegebenen Ordner gefunden werden. Für die Transformation von LESS zu CSS ist die LessTransform-Klasse zuständig. Die Klasse verwendet die Dotless-API zum Parsen von LESS-Skripts. Der Code für „LessTransform“ ist recht einfach:

public class LessTransform : IBundleTransform
{
  public void Process(BundleContext context, BundleResponse response)
  {
    response.Content = dotless.Core.Less.Parse(response.Content);
    response.ContentType = "text/css";
  }
}

Weitere intelligente Tools

Außer LESS gibt es noch andere Tools zur CSS-Vorverarbeitung. Ebenfalls verbreitet ist Syntactically Awesome Stylesheets (Sass, sass-lang.com), um nur ein Beispiel zu nennen. Das Resümee ist, dass Sie für die umfangreiche Webprogrammierung unabhängig vom Tool unbedingt einen CSS-Präprozessor berücksichtigen sollten. Intelligentere Tools zum Verwalten und Organisieren von CSS-Code sind fast eine Notwendigkeit, ob Sie nun Grafikdesigner oder Entwickler sind. Die Tools sind noch besser, wenn sie auch in die Webplattform integriert sind. Als Letztes möchte ich noch darauf hinweisen, dass Visual Studio 2012 und Visual Studio 2013 durch die Web Essentials-Erweiterung eine hervorragende Unterstützung für LESS (und verwandte Technologien) bieten. Sie können die Erweiterung unter vswebessentials.com herunterladen. Der LESS-Editor ist außerdem in Visual Studio 2012 Update 2 und in Visual Studio 2013 verfügbar.

Dino Esposito ist der Autor von „Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) sowie des in Kürze erscheinenden „Programming ASP.NET MVC 5” (Microsoft Press). Esposito ist Technical Evangelist für die .NET- und Android-Plattformen bei JetBrains und spricht häufig auf Branchenveranstaltungen weltweit. Auf software2cents.wordpress.com und auf Twitter unter twitter.com/despos lässt er uns wissen, welche Softwarevision er verfolgt.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Mads Kristensen (Microsoft)
Mads Kristensen ist Program Manager im Web Platforms & Tools-Team bei Microsoft und beschäftigt sich mit den Webentwicklererfahrungen von Visual Studio. Er verfügt über mehr als zehn Jahre Erfahrung mit der Entwicklung von Webanwendungen auf der Microsoft-Plattform. Kristensen ist Gründer des Open-Source-Projekts BlogEngine.NET, die sich mit weltweit 800.000 Benutzern zur meistverbreiteten Bloganwendung auf der ASP.NET-Plattform entwickelt hat. Er hat zudem einige beliebte Visual Studio-Erweiterungen erstellt, darunter Web Essentials, Image Optimizer und CssCop.