Material: theme: average size of 315 KB for one theme is too large

Created on 26 Jun 2016  路  8Comments  路  Source: angular/material

We have noticed, while working on static theming, that the average theming stylesheet for only one theme is about 315 KB big.

The plain theme stylesheet from the $MD_THEME_CSS constant is about 50 KB big.

So there is a huge difference between the _compiled_ and _base_ CSS.

We have to take look at the generated theme stylesheets and probably find some unnecessary selectors etc.

important investigation performance performance

All 8 comments

Is this due to the mediaQuery selectors in Layouts ?

No, the layouts are not included in those stylesheets, so it probably relates to the theming provider.

Also to mention that there's a lot of nesting in the theming files. Here's an example:

md-radio-group.md-default-theme.md-hue-1:not([disabled]) .md-primary .md-checked ._md-off,
md-radio-group.md-hue-1:not([disabled]) .md-primary .md-checked ._md-off,
md-radio-group.md-default-theme.md-hue-1:not([disabled]) .md-primary.md-checked ._md-off,
md-radio-group.md-hue-1:not([disabled]) .md-primary.md-checked ._md-off,
md-radio-group.md-default-theme.md-hue-1:not([disabled]).md-primary .md-checked ._md-off,
md-radio-group.md-hue-1:not([disabled]).md-primary .md-checked ._md-off,
md-radio-group.md-default-theme.md-hue-1:not([disabled]).md-primary.md-checked ._md-off,
md-radio-group.md-hue-1:not([disabled]).md-primary.md-checked ._md-off,
md-radio-button.md-default-theme.md-hue-1:not([disabled]) .md-primary .md-checked ._md-off,
md-radio-button.md-hue-1:not([disabled]) .md-primary .md-checked ._md-off,
md-radio-button.md-default-theme.md-hue-1:not([disabled]) .md-primary.md-checked ._md-off,
md-radio-button.md-hue-1:not([disabled]) .md-primary.md-checked ._md-off,
md-radio-button.md-default-theme.md-hue-1:not([disabled]).md-primary .md-checked ._md-off,
md-radio-button.md-hue-1:not([disabled]).md-primary .md-checked ._md-off,
md-radio-button.md-default-theme.md-hue-1:not([disabled]).md-primary.md-checked ._md-off,
md-radio-button.md-hue-1:not([disabled]).md-primary.md-checked ._md-off {
    border-color: rgba(100, 181, 246, 0.87);
}

Yep, when I was looking at fixing the contrast/dark themes, I realized this and was worried about performance. I don't have benchmark numbers but I don't see performance reduction from heavy themes.

That being said, there is a much more efficient way of doing theming. There are a lot of overlapping rules. We can unify all the rules with class names instead. Then, we can add class names to elements. For example, we can have a class name such as .md-theme-background-contrast-divider and add that to all relevant elements..

The problem is that there is no "class map" file. You would have to add these classes in the element directive/controller .js file. This makes theming much more integrated than having a separate .scss file.

Of course, I can also write something into generateTheme to generate classes automatically and try to compress them.

But I'm not sure performance is affected too much. Before md-colors, I generated a theme for each palette, and didn't see any performance difference. The only problem is the slightly longer load time because of the task of generating all the themes. I worked around that with a pure CSS loading spinner while Angular loaded.

@crisbeto - what is the status and targeted solution for this?

We haven't really looked into it yet @ThomasBurleson. Me, @DevVersion and @EladBezalel discussed it briefly and decided that a good start could be to go through and clean out some of the unnecessary nesting in the theme files.

I had some time so I tried combining selectors that have the same style declarations. It helps a little. but it's definitely not the main culprit for the combined file size. These are the reductions:

  • Non minified got reduced about 50kb (308kb -> 256kb).
  • Minified got reduced by 25kb (275kb -> 250kb).

For reference, here's the script that I ran:

var postcss = require('postcss');
var fs = require('fs');
var merge = postcss([ require('postcss-merge-selectors') ]);
var filename = 'theme';

merge.process(fs.readFileSync(`./${filename}.css`).toString()).then(result => {
    fs.writeFileSync(`./${filename}.comb.css`, result.css);
});

Adjusting autoprefix settings in PR https://github.com/angular/material/pull/11340 saved us 38 KB on the minified css bundle (details).

But it is still too large and we should investigate further approaching to shrinking it. There is still considerable nesting and duplication.

We should look more into applying the changes from https://github.com/angular/material/issues/8860#issuecomment-235493044 as well.

Was this page helpful?
0 / 5 - 0 ratings