Identify unused CSS

Unused CSS

Recently finished a new page design? We all know how cluttered code can get when dealing with problems in the design and during the development process. Often, CSS class declarations that were written for elements that were removed from your html page are not removed from the CSS too, and remain as pointless entries in your CSS file, increasing its size and volume of clutter unnecessarily.

Therefore, I have written a small PHP script that uses several regular expressions to check the styles of a page you specify, and tell you which CSS classes remain in your CSS file(s) but are not ustilised in the HTML code. After being told these useless CSS entries, you can manually remove them from your CSS file(s). For now I will just post the code of this file up, so you can use it on your server if you wish. I would host it on the GoSquared server but this script is somewhat vulnerable to cross-site scripting attacks and the like, and has not been designed with security in mind. It is merely a tool. Therefore, I advise you to make sure only you can access this file on your server, and don’t make it public, if you use it on your server.


Identify unused CSS

Main code: by Geoff
Bug fix & more: by Damian
Further development, bug fixes and additions by Geoff

CSS Scanner will look for and scan any embedded or external CSS files in your HTML code.

"; public $page_content = ''; public $unused = array(); public $multi_page; public $page; public $page_content_visual; function __construct($page){ //$multi_css = explode(',', $css); if(empty($page)){ echo "No page specified to scan" . $this->helptext; exit; } $this->multi_page = explode(',', $page); //$css_content = ''; if(count($this->multi_page) > 1){ $i = 0; $this->page_content = array(); foreach ($this->multi_page as $page) { $this->page_content[$i] = file_get_contents($page); $i++; } } else{ //$css_content .= file_get_contents($css); $this->page = $page; $this->page_content = file_get_contents($page); } if(is_array($this->page_content)){ $i=0; foreach($this->page_content as $page_content){ $this->page = $this->multi_page[$i]; $this->page_content_visual = $page_content; $this->unused = $this->scan($page_content); $this->print_report(); $i++; } } else{ $this->page_content_visual = $this->page_content; $this->unused = $this->scan($this->page_content); $this->print_report(); } } function scan($page_content){ $i = 0; if(ereg("n*(.n*)*", $page_content)){ if(preg_match_all("/(@s*imports* (url(("|')?)?(("|')?)|("|'){1}).+("|')?)?)/", $page_content, $ext_stylesheets)){ foreach($ext_stylesheets[0] as $stylesheet){ $css_content[$i] = preg_replace("/(@s*imports*)|(url(?(("|')?))|("|'){1}|)?("|')?;|(s)/", "", $stylesheet); $i++; } $array = 1; } $inline_notused = $this->check_file($page_content, $page_content); } else die("No page styles, sorry!".$this->helptext); $unused = array('internal' => array(), 'external' => array()); if(isset($array) && $array == 1){ foreach($css_content as $css_file){ $css = file_get_contents($css_file); if(!empty($css)){ $not_used = $this->check_file($css, $page_content); array_push($unused['external'], array('css_file' => $css_file, 'external' => $not_used)); } } } if($inline_notused != false){ $unused['internal'] = $inline_notused; } return $unused; } function print_report(){ echo "

Report for page: ".$this->page.'

'; foreach($this->unused['external'] as $unused){ echo 'CSS entries not used from external CSS file '.$unused['css_file'].':
'; if(count($unused['external']) > 0){ foreach($unused['external'] as $entry){ echo $entry.'
'; } }else echo 'None, good job!'; echo '

'; } if(count($this->unused['internal'] > 0)){ echo 'CSS entries not used from internal CSS code block:
'; foreach($this->unused['internal'] as $entry){ echo $entry.'
'; } echo '

'; } if(isset($_GET["visual"]) && $_GET['visual'] == 'iframe'){ echo "
"; } elseif(isset($_GET["visual"]) && $_GET['visual'] == 'inline'){ echo "
", $this->page_content_visual; } } function check_file($css, $page_content){ preg_match_all("/.([a-zA-Z-_][a-zA-Z0-9-_]+)({|[s].*{)/", $css, $css_classes); preg_match_all("/#([a-zA-Z-_][a-zA-Z0-9-_]+)({|[s][^;]*{)/", $css, $css_ids ); preg_match_all("/<[a-zA-z0-9][^>]*classs*=s*["'](.+?)["']/", $page_content, $page_classes); preg_match_all("/<[a-zA-z0-9][^>]*ids*=s*["'](.+?)["']/", $page_content, $page_ids); $clean_page_classes = array(); $clean_page_ids = array(); foreach($page_classes[1] as $s) { $classes = explode(" ", $s); foreach($classes as $class) { array_push($clean_page_classes, $class); } } foreach($page_ids[1] as $s) { $ids = explode(" ", $s); foreach($ids as $id) { array_push($clean_page_ids, $id); } } $not_used = array(); foreach($css_classes[1] as $css){ if(!in_array($css, $clean_page_classes) && !in_array('.'.$css, $not_used)){ array_push($not_used, '.'.$css); } } foreach($css_ids[1] as $css){ if(!in_array($css, $clean_page_ids) && !in_array('#'.$css, $not_used)){ array_push($not_used, '#'.$css); } } return (count($not_used) > 0) ? $not_used : false; } } $scanner = new css_scanner($_GET['page']); ?>

Feel free to test it and suggest improvements.

USAGE: You can use this script in a couple of ways. In the querystring, you can do:
The script will attempt to detect styles that are imported into your page. The script will use external css files included using

or similar;

As I said, do not make this script public on your server. Use it as your own private tool. You have been warned!

This script is free. Use at your own risk.

GoSquared cannot be held responsible for any problems that may be caused through the usage of this script.