In a previous post I detailed an unexpected feature in a past version of Google Chrome DevTools that allowed the coverage tool to persist across pages of a website.

It was very useful because it allowed you to then export the coverage report and parse out all the unused CSS styles (with a bit of care – taking into account dynamic and @media styles). Unfortunately it was an unintended bug that the developers “fixed”.

Moving on, there is another way to export CSS coverage across pages using a tool called Puppeteer.

Automated Browser Testing

Puppeteer is a way to automate and script tasks within Chrome. There are many uses for this such as scraping, taking screenshots, exporting as PDF files. Basically anything that you can do manually in Chrome can be automated in Puppeteer. It’s a Node library that allows scripts to access the DevTools API.

If you are looking to optimise a bloated CSS stylesheet(s) then Puppeteer can be used to get the coverage report out of DevTools and persist across pages.

CSS Coverage Strategy

When parsing out unused CSS styles I think you need to develop some sort of strategy as the process isn’t perfect, things like @media styles might need to be excluded as well as pseudo styles for things like nav bars or accordions.

It’s useful to separate your stylesheets, for example you can put all your nav bar rules in one file then omit them from the coverage report. Same goes for @media styles though they are a bit tricky as they can appear anywhere in a stylesheet. Realise that you aren’t going to get a 100% optimised stylesheet and that somewhere along the line there is going to be some bloat.

Scripting Puppeteer

The first task is to set up a Node script to control Puppeteer. What we want it to do is start coverage then navigate to a range of pages and finally export the coverage report to a JSON file – much like what the coverage tool can do manually when you press F12 to open DevTools.

Persist Coverage across pages

The line below will start CSS coverage. Luckily it has an option called ‘resetOnNavigation’ which we want to set to false. This is perhaps the most important bit as it will allow the coverage tool to collect rules across pages, much like the bug in Chrome did.

await page.coverage.startCSSCoverage({ resetOnNavigation: false });

If you have built a site on a CSS framework like Bootstrap, you can also get Puppeteer to resize itself, emulating in a sense table and mobile devices. You would set your viewport width to 1px under the breakpoint (768px in this example for medium or md devices in bootstrap).

await page.setViewport({
width: 767,
height: 600,
deviceScaleFactor: 2,

You might also want to get the browser to scroll to the bottom of the page, or even emulate hovering over an element, thus triggering ::hover styles.

A full example can be found here