Ungenutztes CSS entfernen mit uncss (gulp)

Google Chrome - Audits Tab

Die Größe von CSS-Dokumenten ist 2014 im Durchschnitt um 24% von 46kb auf 57kb gestiegen. Ein Anstieg um fast ein Viertel der Gesamtgröße ist echt nicht ohne. Natürlich könnte man sagen, dass sich CSS stark weiterentwickelt hat und wir viel mehr Möglichkeiten haben Aufgaben, die wir vorher mit Javascript gelöst hätten, mit CSS umzusetzen. Leider ist nur die Größe von Javascript-Dokumenten ebenfalls gestiegen, um 7% im Schnitt.

What surprises me most is CSS’s 11Kb rise. Responsive Web Design and CSS3 animations could account for some of this increase but there’s not been a drop in JavaScript.

http://www.sitepoint.com/average-page-weight-increases-15-2014/

Es handelt sich hierbei um eine negative Entwicklung der wir zumindest ein bisschen entgegenwirken können. Zuerst müssen wir erkennen, ob und warum unsere CSS Dateien so groß sind und schließlich was wir dagegen tun können.

Das Problem

Das größte Problem stellen meist nicht eine Handvoll ungenutzter Klassen im eigenen CSS dar, sondern das CSS externer Plugins, Libraries oder Frameworks. Wie viel nutzt man tatsächlich von all den Eigenschaften, die in Foundation oder Bootstrap definiert sind? Oftmals nur sehr wenig. Auf matuzo.at beispielsweise verwende ich ein kostenloses Theme, das auf Bootstrap aufbaut. Von den 111kb, die allein das bootstrap CSS-Dokument groß ist, nutze ich nur 9%, also knapp 10kb. Der Rest liegt nur da und verschlechtert die Performance und damit auch die Usability meiner Website.

Herausfinden wie viel CSS nicht genutzt wird

In Chrome kann man recht einfach erfahren, wie viel des eingebunden CSS nicht verwendet wird. Dafür öffnet man die DevTools, wechselt auf den Audits-Tab und klickt unten auf Run. Unter Web Page Performance gibt es dann einen Punkt Remove unused CSS rules, den man aufklappen kann. Da sind die einzelnen CSS Dateien und die jeweilige Prozentzahl des ungenutzten CSS aufgelistet.

DevTools öffnen

Die DevTools lassen sich mit Command + ALT + I öffnen.

+ + I

Audits-Tab in den Dev Tools

Google Chrome - Audits Tab

Die Lösung: Ungenutztes CSS entfernen

Die oder zumindest eine Lösung ist uncss. uncss durchforstet die Dokumente einer Website und entfernt ungenutzte CSS Regeln aus den Stylesheets. Dabei checkt es welche der definierten Regeln in den Dokumenten vorkommen. Sogar durch Javascript hinzugefügtes CSS wird dabei beachtet.

uncss kann man unterschiedlich nutzen:

Folgend habe ich ein Beispiel mit gulp-uncss vorbereitet.

Hinweis: Dieser Beitrag deckt die Installation von gulp und die Grundlagen der Benutzung nicht ab. Diese habe ich aber hier beschrieben.

gulp-uncss: Installation

gulp-uncss kann man via npm installieren und als dev-dependency speichern.

npm install gulp-uncss --save-dev

gulp-uncss: Task erstellen

Zu Beginn binden wir gulp und gulp-uncss ein und erstellen einen einfachen Task, den wir uncss nennen.

var gulp = require('gulp'),
    uncss = require('gulp-uncss');

gulp.task('uncss', function() {

});

Der Task soll alle CSS Dateien unseres Projekts durchforsten. Dafür kann man entweder ein Array mit bestimmten Dateien definieren oder Ordner, die nach CSS Dateien durchsucht werden sollen.

Array mit Dateien übergeben

return gulp.src(['dev/site.css', 'dev/plugin.css'])

Ordner nach Dateien mit der Endung .css durchsuchen

return gulp.src(dev/*.css')

Danach führen wir uncss aus und definieren mit gulp.dest den Ordner in den die optimierten Dateien verschoben werden sollen.

var gulp = require('gulp'),
    uncss = require('gulp-uncss');

gulp.task('uncss', function() {
    return gulp.src('dev/*.css')
        .pipe(uncss())
        .pipe(gulp.dest('dist'));
});

Der Task würde, wenn man ihn ausführt, zu Fehlern führen, weil man uncss mitteilen muss, welche Dateien durchsucht werden sollen. Das macht man indem man ein Array mit den Dateinamen übergibt.

.pipe(uncss( {
    html: ['*.html'],
}))

*.html steht für alle Dateien mit der Endung .html im root-Ordner.
Und das war es eigentlich schon. Alle CSS-Dateien im dev Ordner werden durchsucht und wenn es CSS Eigenschaften gibt, die im HTML nicht aufgerufen werden, werden sie aus dem optimierten CSS-Dokument, das im dist Ordner gespeichert wird, entfernt.

Besonderheiten und Einstellungen

Javascript Dateien

Bei größeren Projekten kann es notwendig sein, dass man dem Task zusätzliche Zeit geben muss, um das Javascript auszuführen. Dafür kann man mit timeout in Millisekunden angeben wie lange man warten möchte bis das Javascript verarbeitet worden ist.

.pipe(uncss( {
    html: ['*.html'],
    timeout: 2000
}))

Wenn man Javascript-Dateien mit relativen Pfaden einbindet, werden sie nicht durchsucht. Eine Lösung, die ich gefunden habe, ist, dass man der html-Option zusätzlich zu den HTML-Dateien auch noch den absoluten Pfad zum Projekt übergibt. So werden auch die eingebunden Javascript-Dateien durchsucht.

html: ['*.html', 'http://localhost/meinprojekt'],

CSS-Eigenschaften, die nur bei Userinteraktion, also beispielweise bei click, Anwendung finden, werden nicht beachtet. Mann muss explizit angeben, dass diese bei der Optimierung ignoriert werden sollen.

Eigenschaften ignorieren

Es gibt zwei Möglichkeiten Eigenschaften zu ignorieren.

Im CSS

.klasse19 { background: green;}
/* uncss:ignore */
.klasse20 { background: green;}
.klasse21 { background: green;} 

Mit Hilfe des Kommentars /* uncss:ignore */ wird die Klasse .klasse20 ins CSS geschrieben, selbst wenn sie nirgends aufgerufen wird.

Im gulp Task

Man kann auch direkt im gulp Task definieren, welche Deklarationen auf jeden Fall eingebunden werden sollen. Entweder man übergibt den kompletten Selektor oder eine Regular Expression.

ignore: ['h1', /^.js-/]

/^.js-/ würde alle Klassen ignorieren, die mit .js- beginnen.

Eine komplette Liste der Einstellungen gibt es hier: https://github.com/giakki/uncss#from-the-command-line

Das fertige Beispiel

var gulp = require('gulp'),
    uncss = require('gulp-uncss');

gulp.task('uncss', function() {
    return gulp.src('dev/*.css')
        .pipe(uncss({
            html: ['*.html', 'http://localhost/meinprojekt'],
            ignore: ['h1', /^.js-/]
        }))
        .pipe(gulp.dest('dist'));
});

Eine funktionierende Demo habe ich auf Github geladen. Um sie selber zu testen, muss man im Terminal mit cd in den Projektordner wechseln und dann mit npm install die Dependencies herunterladen. Bevor man den Task mit gulp uncss ausführt, muss man der Variable pathToProject den absoluten Pfad zum Projektordner übergeben.

Fazit

Zwar handelt es sich hier nur um ein sehr einfaches Beispiel, aber man sieht, dass es durchaus Sinn machen kann mit uncss zu arbeiten. Wenn einem Performance wichtig ist – und das sollte es – muss man diesen Schritt fast zwingend in den eigenen Workflow integrieren. Was man mit uncss bewirken kann sieht man außerdem auch in Addy Osmanis Talk auf der CSSconf EU (Die passenden Slides dazu gibt es auf speakerdeck.com).

Credits

Header-Foto gefunden auf Pixabay.

Manuel Matuzovic

Frontend Developer aus Wien.

Schreibe einen Kommentar

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