Tags:

Optimize CSS Styles in Magento

Magento/OpenMage has a default feature to merge all CSS files into one which was implemented back in the old days to reduce HTTP requests and therewith improve the performance for the client. Nowadays with HTTP/2 (or even HTTP/3) the number of requests is not that important anymore (and on the contrary a certain number of parallel asset downloads should be preferred), but there are many other ways the CSS asset delivery can be improved in Magento. Let's see how!

Chris / / last updated on

This blog post is a follow-up of my original description of the perfect Magento frontend in 2023. In that previous post I described several measures to improve the CSS in the Magento frontend like Critical Path optimization or the use of utility-based CSS classes which are all very important things.
Now we want to have a look at how to optimize CSS delivery by improving asset minification.

Why optimize CSS styles?

You may ask why it is still beneficial to minify the CSS files at all. Nowadays browsers and webservers like Apache, nginx or Litespeed are able to compress content via gzip or brotli before transmission very effectively.
But netherless by minifying and reducing the amount of CSS code on our side we are able to influence the performance even more than simply compressing files: imagine for example code comments which can be removed, rewrite and combine CSS statements to use less selectors/code and remove unused CSS selectors.

In addition optimizing CSS is very important especially for the Critical Path CSS as this influences all relevant performance metrics in Lighthouse like TTFB or LCP. CSS is one of the few elements that the browser definitely requires as early as possible in order to properly display your website. That's why the browser considers CSS as a blocking resource.

And of course the best code is the one that is not written (or not shipped to customer)!

From CSS Pre-Processors to Post-Processors

I used the CSS pre-processor Sass for years extensively and liked it very much. The number one reason for this was nesting, so vanilla CSS was not able to do things like this which is absolutely required for component-based styling:

.card {
    .header {
        font-weight: bold;
    }
}

Besides that there are many more useful Sass features like mixins, variables, calculations, etc. that made the overhead of compiling the Sass language into CSS a no-brainer.

But nowadays also the CSS world is not at a halt and we have lots of exciting new features in the CSS standard that allows to skip the additional pre-processing step in the build pipeline.

The main benefit of using a CSS post-processor instead of pre-processors: I favor to work with the pure CSS standard and getting to know upcoming CSS features as early as possible instead of learning a different pre-processor language.

Of course not all Sass features can be replicated in plain vanilla CSS that's why post-processors like the most popular PostCSS come into play.
In addition there is also the history-long problem of thousands of different browser versions and their implementation status of these CSS features. So it is also mainly a question of which browsers do you want to support for your users.
The following table shows my most-used Sass features together with their vanilla CSS equivalents (the same comparison which I already did for JavaScript as well):

Sass Feature CSS Equivalent
Variables like $_color-dark: #000 CSS Variables with var(--color-dark)
Mixins with @include svg-icon() PostCSS Mixin-Plugin using @mixin svg-icon
Calculations CSS calc() function

Best CSS File Structure in Magento

For this purpose I can recommend the extension Aoe_JsCssTstamp which basically improves 2 things compared to original Magento behaviour:

  1. Possibility to influence the CSS file name and e.g. add file content hash, version string or store id like s.2fd49f2ddcfae8a2536d440318d4f7cf.css. This makes cache invalidation e.g. in a content delivery network (CDN) or end user browser very easy.
  2. Additionally look for pre-generated minified versions of CSS files.

In general I would aim for generating only a single CSS file in our CSS asset pipeline for several reasons:

  • Most obviously: simplicity. If we only generate one target file, we can apply all the optimízations with PostCSS to this single file only and don't have to mess up with complicate configurations.
  • By removing unused CSS (see below) we already have the only absolute necessary styles in our file so there is minimal benefit of splitting this up further more.
  • What can make sense is to create separate files for different media queries because these then can be loaded asynchronously by the browser by default - this is also what Magento 2 does.

Using PurgeCSS with Magento

With the help of the second point we can build a local minification pipeline and then store the generated minified CSS files in a folder like minified/css. Then we can configure the extension to use that folder for our minified versions. Keep in mind that the folder structure below minified/css has to match the one in the skin folder.

For the build pipeline I simply use grunt, but any other tool or simple script is also possible. First we have to install some dependencies:

npm i --save-dev grunt grunt-contrib-cssmin grunt-purgecss

In the Gruntfile I simply use 2 tasks. The first one is the minification of the CSS files:

cssmin: {
    skin_css: {
        files: [{
            expand: true,
            cwd: 'src/vianetz/theme/src/',
            src: ['skin/frontend/default/vianetz/**/*.css', '!**/*.min.css', '!**/_*.css'],
            dest: 'htdocs/minified/css',
            ext: '.min.css'
        }]
    }
},

The second task is the purging. Therefore I use the tool PurgeCSS which allows to scan HTML content (Magento's .phtml template files) and CSS files and remove which CSS selectors are not in use. You can configure which selectors should not be purged even using regex.

In order not to purge CSS selectors that are in use in Magento CMS Blocks or Pages, there are several possibilities to choose from:

  • Do a live database dump into data/cms_blocks_pages_live.csv and include that as content parameter for PurgeCSS
  • If you use a Full Page Cache (FPC) like Lesti_Fpc for Magento another possibility is to use the (warmed) FPC cache contents from your production server and use these HTML contents as input for PurgeCSS (this is my preferred method)

So this is the resulting sample Gruntfile.js part:

purgecss: {
    minified_css: {
        options: {
            content: ['./htdocs/app/design/frontend/base/default/template/**/*.phtml', './src/vianetz/**/*.phtml', './data/cms_blocks_pages_live.csv'],
            dynamicAttributes: ["aria-selected"],
            safelist: {
            'standard': [
                'kbd',
                'blockquote'
            ],
            'deep': [
                /^body.*/,
                /^address-select/,
                /^checkout-step-*/
            ]
            }
        },
        files: [{
            expand: true,
            src: ['htdocs/minified/css/skin/frontend/default/vianetz/css/**/*.min.css'],
            dest: '.'
        }]
    }
}

The Result

By using this simple asset minification pipeline I was able to reduce the CSS size of the homepage of vianetz.com by nearly 30%. You're right the configuration for the purging is a bit tricky as you have to take care that no selectors are missed. So it takes some time to tweak the PurgeCSS safelist config but a reduction of nearly a third of shipped CSS is definitely worth it.
Of course this heavily depends on your used CSS but as there are a lot of CSS frameworks like Bootstrap etc. used out there, the possibility is high that the percentage is a big one. So you should definitely try it!

After we have now reduced the CSS file sizes to a maximum, in one of the next blog posts we will have a look at how we can further improve CSS delivery by using the very interesting HTTP/2 Early Hints feature.


Post Comments to "Optimize CSS Styles in Magento"

Submit Comment

With the use of this comment form you agree to the saving and processing of your data by this website. More information about the processing of your data can be found in our privacy statement.
Your data will be transmitted securely via SSL.

Meine Magento Extension Bestseller