homeASCIIcasts

180: Finding Unused CSS 

(view original Railscast)

Other translations: Cn It

Any medium or large-sized website probably has a large amount of CSS spread across one or more stylesheets and the chances are that there are selectors in those stylesheets that are no longer used on any of the pages in that site. These selectors should be removed but they rarely are as there’s always a small risk that they’re still used somewhere on the site. Fortunately a couple of useful tools exist to search through a site and find any unused CSS and we’ll take a look at them in this episode.

Dust-Me Selectors

The first solution we’ll look at is a Firefox plugin called Dust-Me Selectors. Once it’s installed we can visit a web page, click the pink brush in the status bar at the bottom and Dust-Me Selectors will scan through the page’s stylesheets and pop up a report that shows the unused selectors on that page.

Dust Me Selectors’ results for a page

Of course some CSS selectors might be marked as unused as the elements that match them are on other pages. To help with this Dust-Me selectors has a Spider Log tab which can take the URL of a sitemap file. Dust Me Selectors will then report on the selectors that weren’t found on any of the pages in the sitemap which will give us a more accurate report about the CSS selectors that aren’t used in our site.

Deadweight

Dust-Me Selectors is a good solution for looking for unused CSS selectors across a website but what if we’re looking for a solution that integrates more tightly with a Ruby on Rails application and which we can have more control over scripting? This is where a gem called Deadweight comes in. It does exactly what we want, searching through a Rails application’s CSS for unused selectors and using Ruby code to specify the pages and stylesheets to parse.

To install the gem we first need to ensure that we have Github in our sources list. If not we can add it with

gem sources -a http://gems.github.com

Once it’s added we can install the gem.

sudo gem install aanand-deadweight

Creating a rake Task

The usual way to run Deadweight is as a rake task, so we’ll create a deadweight.rake file in our application’s /lib/tasks directory to do this.

At the top of the file we’ll need to require the Deadweight gem. We have to be careful when requiring gems in rake tasks. If we don’t have the gem installed, say on our production server, then every rake task will break. To protect against this we’ll wrap the require statement in a begin/rescue block.

begin
  require 'deadweight'
rescue LoadError
end

We can now write the rest of the task.

desc "run Deadweight (requires script/server)"
task :deadweight do
  dw = Deadweight.new
  dw.stylesheets = ['/stylesheets/application.css']
  dw.pages = ['/']
  puts dw.run
end

We start by adding a description of the task, then create the task itself. This creates a new instance of Deadweight then specifies the full path to the stylesheets and pages that should be parsed. We finish by outputting the results of the Deadweight run.

Note from the description that we need to have start script/server to run our rake task. With the server running we can try out our task.

$ rake deadweight
(in /Users/eifion/rails/asciicasts)
/stylesheets/application.css
/
  html
  body
  h1
  ...
found 31 unused selectors out of 60 total
h2 a
code
pre
form.searchForm input[type=text]
form.searchForm input[type=submit]
...

The (truncated) output above shows a list of the selectors that are matched on a page followed by a list of those for which no match was found. There are 31 unused selectors in the list above, but we’re only checking for matching selectors on the home page so we should add more of the pages from our application to the array of pages that Deadwood searches. One way to work out which pages we should be searching is to use rake routes to see a list of the routes in our application.

To get a more accurate view of the unused selectors in our stylesheets we’ll add a few more pages from our site to the array of pages. It’s not a complete list, but it’s enough to cover most of the site.

dw.pages = ['/', '/episodes/all', '/about', '/episodes/150-rails-metal', '/episodes/155-beginning-with-cucumber', '/search/index']

If we run rake deadweight again it will run through the pages we’ve supplied and we’ll see a shorter list of unmatched selectors. (Again this list has been cut down here.)

$ rake deadweight
(in /Users/eifion/rails/asciicasts)
/stylesheets/application.css
/
  html
  body
  h1
  ...
/episodes/all
  dl#episodeArchive dt
  dl#episodeArchive dd
/about
/episodes/150-rails-metal
  h2 a
  code
  pre
  ...
/search/index
found 10 unused selectors out of 60 total
form.searchForm input[type=text]
form.searchForm input[type=submit]
code.terminal
...

If there are selectors that we know are used in a site, but which only show under certain circumstances, such as selectors used to display error messages or flash notifications we can use ignore_selectors to exclude them from the results.

dw.ignore_selectors = /flash_notice|flash_error|errorExplanation|fieldWithErrors/

When we run rake deadweight now it will return an even smaller list of unmatched selectors. We now have few enough to be able to manually work through them and remove the ones we know aren’t used. For the ones we’re not sure about we could use TextMate’s Find In Project option (or whatever similar feature your favourite text editor provides). to search through the site to see if there are any matches.

That’s all for this episode. We’ve covered most of the basic features of Deadweight, but there are some advanced options that are worth looking at too. These are detailed on Deadweight’s GitHub page.