Clean your CSS from unused selectors

Have you ever experienced any of these scenarios?

  • You run an A/B test and during cleanup you find that some CSS class selectors might be used somewhere else on the website; therefore you don’t want to remove them.
  • You look at the CSS on a page and you don’t know what to remove because some old legacy javascript code might still be using it.
  • During refactoring, you delete the markup but you forget the corresponding CSS.

We’ve all been there. I needed some automated way to look for class usages.

I skimmed through some solutions online but couldn’t find anything we could use on our project.

The problem

We have a Rails project and a separate project for the styleguide. A class that is not used in the project might still be used in the styleguide.

We use Haml for templates and sometimes JST and HBS as JS templates. We also often @extend classes in our SCSS files.

To clean up our css I come up with a simple script to detect unused CSS class selectors:

If you want to use it, just modify line 2, 4 and 34 to match your project setup. Then run clean_css.sh from your project’s directory: it will output the list of classes declared in your css files and a count of usages.

Explanation:

I wanted to extract every CSS selector declared in the current project and look if they are used in Haml, JS and so on in the current project and in the styleguide.

I created a FOLDERS variable with a list of folders the script will use to look the files.

FOLDERS=("app/" "vendor/"  "public/" "../carwow-theme/lib/carwow-theme/app" "../carwow-theme/lib/carwow-theme/vendor")

Then, I extracted all SELECTORS contained in *.css and *.scss files and save them in a file called classes_found.txt.

grep -hr --include "*.css" --include "*.scss" "^\s*\." app/ > tmp.txt
sed -i -e 's/\/\/.*$//' tmp.txt         # remove comments
sed -i -e 's/{.*}//' tmp.txt # remove inline declarations
sed -i -e 's/{//g' tmp.txt # remove open brackets
sed -i -e 's/[,>+]\s*/\n/g' tmp.txt # split class names separated by , > +
sed -i -e 's/ /\n/g' tmp.txt # split any children classes e.g. .class .children
sed -i -e 's/\./\n./g' tmp.txt # split multiple selectors e.g. .aclass.active
sed -i -e 's/^[^.].*$//' tmp.txt        # remove html tag selectors
sed -i -e 's/[:]\{1,2\}.*$//' tmp.txt # remove pseudo selectors e.g. :hover
sed -i -e 's/[#].*$//' tmp.txt # remove ids after classes e.g. .someclass#someid
sed -i '/^$/d' tmp.txt                  # remove empty lines
sed -i -e 's/^\.//' tmp.txt # remove starting dot
sort -u tmp.txt > classes_found.txt # Sort and unique
rm tmp.txt

At this point, I ended up having a file with all the selectors. I also double-check that Silver surfer is installed.

if which ag; then
echo 'Silver surfer found, start looking for matches'
else
echo 'Silver surfer not found, installing it...'
sudo apt-get install silversearcher-ag
fi

Now that I have a list of all classes declared in the project I can start looking for the usage in the FOLDERS defined above.

while read line; do
total=0
for folder in "${FOLDERS[@]}"
do
matches=`ag --file-search-regex "(.*\.haml|.*\.jst|.*\.html|.*\.erb|.*\.js|.*\.coffee|.*\.rb|.*\.hbs)" $line $folder | wc -l`
extend_usages=`ag --file-search-regex ".*.scss" "extend .$line" $folder | wc -l`
total=$((total + matches + extend_usages))
done
if [ "$total" -eq "0" ] 
then
echo "$line $total"
else
echo "- $line $total"
fi
done <classes_found.txt

Notice I look for files with a specific extension:

(.*\.haml|.*\.jst|.*\.html|.*\.erb|.*\.js|.*\.coffee|.*\.rb|.*\.hbs)

The output will go to the console.

Conclusions

This script follows a pretty ‘naive’ approach, it doesn’t find unused ids, it doesn’t find dynamic class names, but gets the work done.

Interested in making an Impact? Join the carwow-team!
Feeling social? Connect with us on Twitter and LinkedIn :-)