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.

* GoSquared ltd.                                    |css_checker.php *
* Authors: Main code by Geoff               *
* Extended by Damian                               *
* Adapted to OOP by Geoff                                            *
* Date: 10/07                                                        *
* Version: 1.2.0                                                     *

class css_scanner{
    public $helptext = "<p>
        <h3>Identify unused CSS</h3>
        Main code: <a href=""></a> by Geoff<br />
        Bug fix & more: <a href=""></a> by Damian<br />
        Further development, bug fixes and additions by Geoff<br />
        <b>Usage:</b><br />
        </ul><br />
        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);
            echo "No page specified to scan" . $this->helptext;

        $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);
            //$css_content .= file_get_contents($css);
            $this->page = $page;
            $this->page_content = file_get_contents($page);

            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->page_content_visual = $this->page_content;
            $this->unused = $this->scan($this->page_content);

    function scan($page_content){
        $i = 0;
        if(ereg("<style( *[n]*.*)>n*(.n*)*</style>", $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);
                $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);
                    $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 "<h1>Report for page: ".$this->page.'</h1>';
        foreach($this->unused['external'] as $unused){
            echo 'CSS entries not used from external CSS file '.$unused['css_file'].':<br />';
            if(count($unused['external']) > 0){
            foreach($unused['external'] as $entry){
                echo $entry.'<br />';
            }else echo 'None, good job!';
            echo '<br /><br />';
        if(count($this->unused['internal'] > 0)){
            echo 'CSS entries not used from internal CSS code block:<br />';
            foreach($this->unused['internal'] as $entry){
                echo $entry.'<br />';
            echo '<br /><br />';
        if(isset($_GET["visual"]) && $_GET['visual'] == 'iframe'){
           echo "<hr><iframe src = "$this->page" width="100%" height="100%"></iframe>";
        elseif(isset($_GET["visual"]) && $_GET['visual'] == 'inline'){
            echo "<hr>",

    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 <style>@import "path to css file";</style> 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.

Subscribe to the GoSquared newsletter.

Join 15,000 people. Get our latest posts delivered to your inbox every week.

  • Well It’s not useful for me, because I use Microsoft Expression Web to code my websites and this app has teh function to remove unused css.
    Good job anyway

  • This is some useful code for some. You should also plug this out on and get some votes for it.

  • Adilson

    Great script!

    Work fine here, using it to check my css in ASP pages.


  • it doesn’t function for php built sites. tried it and it just came up blank when using index.php for page=

  • Pingback: liquidicity » Some people just (don’t) get interfaces…()

  • eric,
    In response to your comment, have you tried the full URL path to the file you want to check, so in the page= bit of the query string. This should work.

  • I found your code very useful, thanks a lot.

    When using the script, I found that some cases were not treated correctly:
    – only the first class / id in the css definition is taken into account
    – multiple class names in the same class attribute were not recognised (resulting in “false positives”)
    – identical class / id will not report even if unused
    (I have the feeling I forgot another issue, but I can’t remember…)

    So I went ahead, corrected these bugs, and added some more features:
    – output prefixed with “.” respectively “#” to distinguish classes and id’s
    – support for multiple html / css pages (as in larger projects) added, use a comma-separated list as “page” parameter
    – added an optional parameter “visual” which will make the script print the evaluated css and html to the browser window.

    The part which looks for CSS definition in the header was left unchanged.

  • Damian,
    This is some excellent work, thanks. As for the problems/bugs you reported, the script wasn’t originally designed to deal with those cases, however I probably should have made it so it would 🙂
    I shall be posting the improved version of the code as soon as I have time.

  • Thanks for the compliments, but without your script I would not have known where to start. Using this basis, it was only finetuning and fiddling with regexp’s to complete it.

    By the way, just in case you’ve already copied the code I posted two days ago, there was a small bug in the regexp preventing it from finding all the classes. This is fixed now.

    As for a future version, one could integrate support for link type css definition

    and probably its quite easy now to evaluate also inline css definitions. But as I won’t use this functionality, I end the development here.

    We are very similar after all – if we don’t need the functionality, we won’t implement it 😉

  • I wanted to illustrate the link type css definition with the corresponding code, but it was stripped by the blog software. Lets see if this works:
    <link rel="stylesheet" type="text/css" href="style.css"/>

  • Des

    Worked great for me. Thanks, guys.

  • Nice idea, exactly what I was looking for. But all it does for me is printing out my external css-file. No comment like “CSS entries not used from” or similar.

  • Damian Version (Post #7) works fine for me!


  • Pingback: Liens de décembre 2007 | SkyMinds.Net()

  • HI i need your help i really want to create my own website/web page but i dont know how to go about doing it so can you please help me outhh

  • thanks.i used it on my website.

  • That’s brilliant work…

    Lukas said,
    July 21, 2007 at 12:29 pm ()

    Well It’s not useful for me, because I use Microsoft Expression Web to code my websites and this app has teh function to remove unused css.
    Good job anyway

    If you’re using a MS product to code your sites you’ve got more to worry about than a straggling CSS element…

  • Ebrahim


    Thanks for the excellent script, but I can’t get it to work. Errors:

    Notice: Undefined index: css in /Volumes/disk2/www/css_redunancy_check.php on line 49
    Notice: Undefined variable: css_content in /Volumes/disk2/www/css_redunancy_check.php on line 55
    Notice: Undefined variable: page_content in /Volumes/disk2/www/css_redunancy_check.php on line 58

    I’m using Damian’s code.


  • Ebrahim, please ensure you are supplying the appropriate (and required) variables in the querystring. Check the help message inside the script for more information, or reply back here if you’re still having problems.

  • nice idea

  • ken

    sounds interesting though. I’ll check it later. All my css is full of junk. Thanks.

  • does this code work? i’ve been looking for a script like this. i guess i’ll give it a whirl!

  • Flak

    Well : php 5.3 says:

    Deprecated: Function ereg() is deprecated in scan.php on line 82

  • vlad


    This is exactly what I’m looking for right now.
    Any updates on the code?
    I can’t access Damian’s code (403 error) and I can’t tell if the code in the blog post is updated or not 🙂

    That being said, I will test it when I get home and provide feedback.

  • Pingback: Remove unused CSS – Affordable CSS Optimizer Service | Hackadelic()

  • Pingback: Detecting Unused CSS Selectors – Part 1 | Refulz PHP()

  • Pingback: Remove unused CSS « Web Resources, Design Inspiration, Freebies, Tutorials, Photoshop, Wordpress |

  • Dan

    This is a great script, this helped me easily find over 30k of unused css classes!

    Very dangerous though, i would certianly keep this one on your private dev servers!

  • Mark

    Can’t get to Damians code – do you have it somewhere? Thanks

  • Inspired Earth

    Hi Geoff, Does this script still work? I see it’s rather dated. If not, is there another way you now go about optimising/removing unused CSS?