Marc Görtz

CSS verkleinern mit CSSTidy

Zum Bloggen gezwungen, wieder mal. Diesmal aber nicht von Ina, sondern vom Kollegen gegenüber. Es geht sich um das Zusammenführen und Verkleinern von CSS-Dateien.

Zunächst einmal stellt sich aber die Frage, warum man das überhaupt tun sollte. Stellen wir uns einmal vor, wir hätten eine ziemlich umfangreiche, gut frequentierte Website, die von mehreren Entwicklern gepflegt wird. Um der einfacheren Pflege halber ein wenig Struktur und Dokumentation in das Projekt zu bringen, teilt man seine CSS-Dateien in logische Abschnitte auf, wie z.B. typography.css, grid.css und colors.css. Diese enthalten natürlich auch eine Unmenge Kommentare, schließlich wollen große Projekte gut dokumentiert sein. Damit schwillen einige Dateien schon mal um ein paar Kilobyte an, was unnötigen Traffic und damit Kosten verursacht. Darüberhinaus entstehen mehrere HTTP-Zugriffe, was Ladezeit kostet. Yahoo! erklärt das recht gut.

Also liegt es nahe, all diese kleinen Dateien zu einer Datei zusammenzufassen und sie zu verkleinern (z.B. Kommentare entfernen, unnötige Zeichen oder unnötigen Whitespace löschen). Hilfreich ist hier neben PHPs eigenen Funktionen die CSSTidy-Klasse. Grob umrissen, ermöglicht sie das Parsen und anschließende Manipulieren von CSS-Dateien.

Beim folgenden PHP-Skript gehen wir davon aus, dass nur die Dateien im »inc«-Verzeichnis unseres CSS-Verzeichnisses zusammengefasst und komprimiert werden sollen. Das macht Sinn, wenn andere, umfassendere Stylesheets auf gemeinsame, logische CSS-Regeln zugreifen sollen. Dass die Pfade natürlich auf die eigene Umgebung angepasst werden müssen, versteht sich von selbst.

<?php
/**
 * Paths
 */
$tidy_directory = dirname(__FILE__) . 'csstidy/';
$css_directory = dirname(__FILE__) . 'css/';
$inc_directory = $css_directory . 'inc/';
$merged_file = 'merge.css';

/**
 * Merge CSS files to one file
 *
 * @param string $inc_directory
 * @param string $target_css_file_name
 */
function mergeCSS($target_directory, $target_css_file_name) {
	if (file_exists($target_directory . $target_css_file_name))
		unlink($target_directory . $target_css_file_name);
	if ($handle = opendir($target_directory)) {
		while (false !== ($inc_file = readdir($handle))) {
			if ((substr($inc_file, -4) === '.css') &&
				($inc_file !== $target_css_file_name))
					file_put_contents(
						$target_directory . $target_css_file_name,
						file_get_contents($target_directory . $inc_file),
						FILE_APPEND
					);
		}
		closedir($handle);
	} else echo('Directory not readable.');
}

/**
 * Compress merged CSS file with CSSTidy
 *
 * @param string $inc_directory
 * @param string $target_css_file_name
 * @param string $tidy_location
 */
function compressCSS($target_directory, $target_css_file_name, $tidy_location) {
	/* Get CSSTidy and the CSS file to compress */
	require_once $tidy_location . 'class.csstidy.php';
	$tidy = new csstidy();
	$css_file = file_get_contents($target_directory . $target_css_file_name);

	/* CSSTidy settings, usage: http://csstidy.sourceforge.net/usage.php */
	$tidy->set_cfg('preserve_css', FALSE);
	$tidy->set_cfg('remove_bslash', TRUE);
	$tidy->set_cfg('compress_colors', TRUE);
	$tidy->set_cfg('lowercase_s', FALSE);
	$tidy->set_cfg('timestamp', FALSE);
	$tidy->set_cfg('optimise_shorthands', 2);
	$tidy->set_cfg('remove_last_;', TRUE);
	$tidy->set_cfg('sort_properties', TRUE);
	$tidy->set_cfg('sort_selectors', FALSE);
	$tidy->set_cfg('merge_selectors', 2);
	$tidy->set_cfg('compress_font', TRUE);
	$tidy->set_cfg('silent', TRUE);
	$tidy->set_cfg('case_properties', 1);

	/* Compression template, template3.tpl = highest compression */
	$tidy->load_template($tidy_location . 'template3.tpl', TRUE);

	/* Parse CSS file with settings and templates */
	$tidy->parse($css_file);

	/* Write parsed output to target file */
	file_put_contents(
		$target_directory . $target_css_file_name,
		$tidy->print->plain()
	);
}

/**
 * Execute functions
 */
mergeCSS($inc_directory, $merged_file);
compressCSS($inc_directory, $merged_file, $tidy_directory);

Das Skript muss dann ausgeführt werden (ob auf Kommandozeile, via URL, über einen Build-Prozess sei Euch überlassen), anschließend wird die neue, komprimierte Datei erstellt oder überschrieben und kann verknüpft werden.

Disclaimer: Ja, ich könnte es noch besser dokumentieren und erklären. Ja, etwas mehr Fehlerbehandlung wäre toll. Ja, es ist nicht das beste PHP aller Zeiten. Ja, man könnte noch validieren, automatisieren, g’zippen… Macht’s einfach besser, dafür ist das Skript als erster Ansatz ja da. ;-)


Erwähnungen

Dieser Bereich ist noch eine Baustelle, sorry.

  1. Marc Jakubowski vor
  2. Mike vor
  3. Marc vor
  4. ff-webdesigner vor