The job of PurgeCSS is to help you to remove unused CSS from bloated stylesheets. I say help you, because it is not intended for use as an automated tool that just works out of the box. It requires human intervention and common sense to get the most out of it.

So how does it work with Joomla? And in particular Joomla 4? There's no documentation on the PurgeCSS site on how to use it with Joomla, and no plugins written for it either.

But don't despair - using PurgeCSS with Joomla is easier than it looks.

What PurgeCSS does

PurgeCSS is really useful if you're using a CSS framework. The figures in the tables below come fromĀ CSS Auditors data (2022), and represent the minified file size of each CSS framework in it's full version.

CSS Frameworks
CSS Framework Minified Size (kB)
Tailwind 2930
Semantic UI 628.29
Primer CSS 591.74
Ant Design 544.07
UI Kit 256.01
CSS Frameworks (cont'd)
CSS Framework Minified Size (kB)
Bulma 205.62
Bootstrap 163.82
Materialize 139.62
Foundation 134.84
Pure CSS 16.79

These frameworks can generate a lot of classes that you don't actually use, and that's where PurgeCSS comes into it's own. It examines the content of your files (typically templates) looking for css class selectors. It then compares those to class selectors found in the css stylesheet you specify.

If a class in the css stylesheet has no match with the content examined, PurgeCSS can be used to remove that selector from the stylesheet. That sounds a bit nuclear, but the way it removes it is entirely up to you. You can have it print out those unused classes to the console, get it to create a brand new stylesheet with those unused classes totally removed or, indeed, remove them from your source stylesheet. Up to you.

There are 2 ways to run PurgeCSS:

  1. via CLI (terminal)
  2. via javascript file (with config file, optional task runner and/or plugins for your specific framework)

Using PurgeCSS CLI with Joomla 4

Good to know

  • The Joomla 4 install I'll be referring to is not using Cassiopeia, but a stand-alone template which we'll call: my_template
  • The stylesheet for my_template was compiled from source files (scss) downloaded from Bootstrap. The point being we are not using any of Joomla's stylesheets for the template

We'll be using the CLI method because it's fast, readable and avoids us having to write a dedicated module or plugin (or pay for one!). To use the CLI, we'll need to install purgecss globally. Open a terminal and enter:

npm i -g purgecss

Second thing is to understand the main options for using the CLI to run PurgeCSS. The ones I'll be using for a Joomla 4 install using the Bootstrap css framework are:

content
The files to examine to find class selectors (typically templates)
css
The stylesheet that PurgeCSS will compare to the class selectors found in content specified above
variables
Frameworks like Bootstrap include variable definitions. You can remove unused variables with this option
safelist
classes that will not be removed by PurgeCSS
output
name/location of the new 'purged' css file. If not specified, will default to std out (terminal)

Building the CLI Command

Content option

Template Files

In this Joomla install the default template is at templates/my_template/. The only files in the root of this folder are the 3 template files - index.php, error.php, and component.php. Here's how the content option would look to get PurgeCSS to scan our template files:

--content templates/my_template/*.php
Template Override Files

If you've overridden templates for any plugins, modules, layouts or components, these will be in the templates/my_templates/html/ folder. So we can use a glob pattern to have PurgeCSS scan any php files in the html folder, including sub-folders. We'll add this as follows:

--content templates/my_template/*.php 
templates/my_template/html/**/*.php

** means recurse into subfolders

Default Plugins, Modules, Layouts, Components

You might also be using some default templates - meaning you have no template overrides for these particular plugins, modules, layouts or components. In this Joomla 4 install we'll be using the default templates for the following:

  • mod_breadcrumbs
  • com_finder
  • Layout - pagination
  • Plugins - Content - Page Navigation

We'll get PurgeCSS to checkout the templates for those as follows:

--content templates/my_template/*.php 
templates/my_template/html/**/*.php modules/mod_breadcrumbs/tmpl/*.php components/com_finder/tmpl/search/*.php layouts/joomla/pagination/l?.php
plugins/content/pagenavigation/tmpl/*.php

l?.php will find link.php, links.php and list.php but not xlinks.php

Javascripts

There is CSS injection from a javascript file in my_template, so we'll have PurgeCSS check that out too:

--content templates/my_template/*.php 
templates/my_template/html/**/*.php
modules/mod_breadcrumbs/tmpl/*.php
components/com_finder/tmpl/search/*.php
layouts/joomla/pagination/l?.php
plugins/content/pagenavigation/tmpl/*.php media/templates/site/my_template/js/injectcss.js

CSS option

I'm going to refer PurgeCSS to the unminified stylesheet for readability. You can use the minified file too, it makes no difference.

--css media/templates/site/my_template/css/bootstrap.css

Variables option

Since Bootstrap specifies a large number of variables in the code (eg --bs-border-radius-lg, --bs-pink) we'll ask PurgeCSS to remove them if they're not being used. The default is not to remove them.

--variables true

Safelist option

I have one class in the stylesheet that I haven't finished styling yet: mycookiebanner. I'll finish it once I've decided what cookie banner I'll install. I don't want PurgeCSS to strip this out for now.

--safelist mycookiebanner

After I ran PurgeCSS, I discovered that Bootstrap's js was injecting a class when a modal was triggered. PurgeCSS couldn't discover that since the Bootstrap js was being imported from a CDN. So, new safelist for future runs of PurgeCSS on this Joomla install:

--safelist mycookiebanner modal-backdrop

Output option

I want PurgeCSS to output it's results to a new stylesheet that I can test with the install called: purged.css. This stylesheet will have all unused class selectors and variables stripped out. I'll put that into the same folder as my template's css for ease of testing:

--output media/templates/site/my_template/css/purged.css

All together now

I opened a terminal in the root folder of the joomla 4 install and entered the following to have PurgeCSS do it's thing:

purgecss --content templates/my_template/*.php templates/my_template/html/**/*.php modules/mod_breadcrumbs/tmpl/*.php components/com_finder/tmpl/search/*.php layouts/joomla/pagination/l?.php plugins/content/pagenavigation/tmpl/*.php media/templates/site/my_template/js/injectcss.js --css media/templates/site/my_template/css/bootstrap.css --variables true --safelist mycookiebanner modal-backdrop --output media/templates/site/my_template/css/purged.css

In the previous examples I put the code on separate lines for readability. You don't need to do that in the CLI.

Results

I tested this visually, and found around 20 missing class selectors. Apart from the missing modal-backdrop css class injected by Bootstrap, the rest had been entered into articles using a text editor. Because they were in the database (content and modules tables, respectively), PurgeCSS had no access to them.

Once I added those to the safelist, PurgeCSS was able to reduce the original 285kB bootstrap.css file to 90kB, and on minification, we ended up at 74kB. Great job PurgeCSS! Anything under 100kB works for me.

Other Approaches

Rejected CSS

It's worth mentioning that PurgeCSS can also output the rejected classes only. This is pretty useful in certain situations. To do this, omit the --output path/to/purged.css and replace that with:
--rejected true (output to console)
--rejected-css path/to/your/rejected.css (output to file)

Using a Script

The Script method can be used in conjunction with the CLI for Joomla 4. This not only preserves the safelist in a file, but allows you to use regex with the safelist as well. The safelist can be divided into standard (as used with CLI), deep, greedy and variables arrays (see how to use them in the PurgeCSS documentation). I've provided a bare bones outline on how to set it all up here.

  1. Create a config file called: purgecss.config.js. Put it wherever you like, but just remember that file paths must be relative to it's location. I put mine into the root of the media/templates/site/my_template folder. And it can stay there, for future use.
  2. Run PurgeCSS as follows: purgecss --config path/to/purgecss.config.js --output path/to/purged.css

Notice we've added a blocklist meaning: these classes are never to be included.

Sample purgecss.config.js
module.exports = {
  content: ['path/to/content/1', 'path/to/content/2'],
  css: ['path/to/stylesheet'],
  variables: [true],
  safelist: {
    standard: [/accordion/,'badge','kbd'],
    deep: [/show$/],
    greedy: [/^modal/],
    variables: ['--bs-blue','--bs-btn-disabled-bg']
  },
  blocklist: [/^navbar/, /blockquote-footer/]
}