Drupal CSS Aggregation

I have often read that Drupal is dumb when it comes to aggregating CSS files and up until recently I took that at face value. However I decided to delve a little into the aggregation routine a little to see exactly what Drupal is doing under the hood.

Unique aggregated file per URL

One thing I thought was told was happening was that when Drupal creates unique aggregated stylesheets per page. It turns out this is not true- no part of the URL makes up the cache ID for the aggregated file. Let’s open up common.inc and see how the cache key is generated.

<?php
function drupal_build_css_cache($css) {
  # .. snip
  $css_data = array();
  foreach ($css as $css_file) {
    $css_data[] = $css_file['data'];
  }
  $key = hash('sha256', serialize($css_data));

  # ... snip
  // Save the updated map.
  $map[$key] = $uri;
  variable_set('drupal_css_cache_files', $map);
}
?>

From what we can see here - the cache key is generated by $css_file['data'] which turns out to be the file names of each css file used to display the page. So while this doesn’t explicitly say “Create a new aggregated file per page” it does say that your CSS files need to be included in the same order for liked pages otherwise a new file will be generated as the hashing algorithm requires the data in the same order to produce the same result.

<?php
$array = array('test', 'test2', 'test3');
// bool (false)
var_dump(hash('sha256', serialize($array)) == hash('sha256', serialize(array_reverse($array))));
?>

GZipping control is provided

GZipping your assets is great as it helps reduce your pages delivery size. However there are some times when you don’t want to GZip your CSS (proxies and firewalls may sometimes have rules preventing them). You can control if Drupal will serve your a Gzipped css file with a variable.

<?php
  if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) {
    # ... snip
?>

If you add the following line to your settings.php file you can disable Gzip compression.

<?php
// settings.php
$conf['css_gzip_compression'] = FALSE;
?>

You can control the stale files

By default Drupal will be configured to purge your aggregated css files every 30 days. This can be controlled as well via your settings.php file. During a cache clear (either cache clear all or cache clear css-js) Drupal will perform drupal_clear_css_cache which will take care of scanning the public://css directory and remove any old css files.

<?php
// settings.php
$conf['drupal_stale_file_threshold'] = 3600;
?>

Setting the configuration variable drupal_stale_file_threshold to 3600 will mean that every hour Drupal will regenerate aggregated css, pretty neat huh? Note: you will want these files cached for longer than one hour - this is just an example

But what doesn’t it do?

The one thing I have seen that modules like advanced aggregationn offer that the default Drupal aggregator does not is the ability to count selectors in your stylesheets. < IE8 enforces a strict 4096 unique css selector limit which can prevent sites from loading if you have overly complex stylesheets.

However modules like advanced aggregation employ more aggressive caching strategies which at times can be harder to purge if you find that you have a style issue affecting a production site.

Drupal CSS Aggregation Drupal CSS drupal_add_css