How BEM encourages inflation of code whereas CSS modules compares reduction of code
/* | |
You have a component called MyComponent.jsx and a decidated "locally scoped" | |
scss file called MyComponent.scss. | |
For one of the HTML nodes you wish to add a clearfix using something like: | |
*/ | |
...:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
/* | |
If you take BEM very literally and you want everything locally scoped you don't | |
really want to use utility functions. So what you might be tempted to do is | |
create a mixins file such as mixins/utilities that contains: | |
*/ | |
@mixin clearFix { | |
&:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
} | |
/* | |
So for your top level node you'll be doing: | |
*/ | |
.MyComponent { | |
@include clearFix; | |
} | |
/* | |
Which outputs the CSS | |
*/ | |
.MyComponent:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
/* | |
But with modules you'd have a generic layout file like this: | |
*/ | |
.clearFix:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
/* | |
Which you'd include by using composes like this | |
*/ | |
.MyComponent { | |
composes: clearFix from utils.scss; | |
} | |
/* | |
That doesn't actually output the above, however, but adds the class `clearFix` | |
to your component instead of the class `MyComponent`. | |
So what happens when you have MyComponent2 and you want to add clearfix to it? | |
Well now with BEM again you want locally-scoped styles so you'll probably use | |
that mixin again and now your code is | |
*/ | |
.MyComponent { | |
@include clearFix; | |
} | |
.MyComponent2 { | |
@include clearFix; | |
} | |
/* | |
Which compiles to: | |
*/ | |
.MyComponent:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
.MyComponent2:after { | |
clear: both; | |
content: "."; | |
display: block; | |
height: 0; | |
overflow: hidden; | |
visibility: hidden; | |
} | |
/* | |
I.e. twice as long! | |
Now you could make the case "well, this is repetion so gzip will solve it. But | |
the problem is you also have double the selectors which is a performance | |
overhead for the browser. | |
Contrast with CSS modules: MyComponent2 simply, again, receives the className | |
"clearfix". You can imagine how effectively this scales. | |
There are solutions to this (e.g. using utility files so you don't have | |
to keep using mixins for BEM-type approaches) but my point is BEM encourages | |
CSS ballooning and at least some attempts to solve that add global scopes. | |
And take it from me; when your project is as large as my last company's and | |
you're dealing with a 15,000 LOC style file and 7,000+ selectors the last thing | |
you need is global selectors! | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment