
BEM Patterns and Anti-Patterns
What’s the most useful file structures
The css file structure of most legacy Rails apps derive from the boilerplate generated scss Rails creates when rails g scaffold is run. We end up with files named admin.scss because we had an admin_controller.rb. This starting place leads us to develop our name spacing in a very top-down way.
We have something like this:
<body class="layout admin">
<div class="panel"></div>
<div class="button"></div>
</body>
// admin.scss
.admin {
.panel {}
.button {}
}
This works for a while, until you want to reuse, or move something in another part or the site’s UI changes with the growing needs of the company. These files get too long without a few patterns, we get a lot of legacy cruft from
Components and the BEM structure promise a more reusable way to construct your UI. One could imagine a fully realized component folder structure.
search/
search.html
search.scss
search.js
search-test.js
button/
button.html
button.scss
button.js
button-test.js
Asset Pipeline not built for that
In Rails, (for load reasons that could probably be changed) our folder structure looks like this:
app/assets/stylesheets/components/*.scss
app/assets/javascripts/components/*.js
app/views/components/*.erb
And we import using * asterisks to ease the pain of making new scss files and have them load in any order so as to not become concerned with the css load order precedence.
In an application.scss we have the following:
// application.scss
@import global/variables;
@import global/mixins;
@import admin; // the original legacy file
@import components/*; // the new stuff that's gonna replace it.
Imports instead of asset pipeline //= requires allow for variables to cross files.
With a structure like this, you start with a big file, 1000’s of lines and you start making smaller files. One per component. Try to use the line number in each file as an indicator of the components complexity. If the file is over 100 lines long maybe there’s a way to break it down into smaller and dumber component children.
Where do we put our @imports?
If you only allow @imports on the root application.scss you won’t have to wonder about load order. The hierarchies flatten out and that’s what we want. Flat rules lead to faster browser paint reflows and smaller file sizes.
// application.scss
@import form;
@import panel;
// form.scss
@import button;
@import input;
// button.scss
@import pill-button;
@import flat-button;
In what order are these component rules loaded? Is panel 2nd or 5th? And why do we need to have all of these files open to see the order? While this looks like it’s organized, having imports within imports adds more complexity than just flatly importing everything in one main file.
Keep the Folders Small
Long directory listings is just as noisy and time consuming as long files.
Again, I like the astrisk * way of importing scss but listing your components in one file works well too. Sometimes you’ll want to leave a few out or ab-test something. I also think it’s great to put all these component css files in semantic folders that make sense. Having 100s of components in 1 folder is a strain on the senses as well. Remember imports take relative paths too:
// application.scss
@import '../components/core/*';
@import '../components/sales/*';
@import '../components/marketing/*';
@import '../components/tutor/*';
@import '../components/client/*';
@import '../components/ab-test-a/*';
// @import '../components/ab-test-b/*';
@mixins and $variables are global
Everything is global using @imports in scss in fact, but placing reusable definitions and variables in a global folder just makes sense. I find files named after their function works best.
global/
colors.scss
mixins.scss
utlities.scss
grid.scss
typography.scss
spacing.scss
normalize.scss
What’s the best way to find & open files?
This is a serious aspect of the decision making with regards to how we break up and name files. We do it a hundred times a day and, in larger apps, sometimes finding the right files to edit on a part of the app you’re not familiar with can take as long as making the edit. There’s some tedium to whittle down here.
Most of us open files using the quick open keyboard short cut, which is Command + T for many of our favorite IDEs. If we search for a particular component, we’ll probably want to guess the HTML will be named the same as the CSS which will be named the same as the JS file. That way they’ll appear in the search and all similar files can be found by simply typing 1 filename.
But that means for every seperated .erb we have (in a Ruby app) we need a matching .scss file. So the desire to group similar component scss (multiple buttons with various modifiers) may be strong to keep directory listings light, but you’ll be giving up the ability to find styles in the file lookup. Though it may still be possible with some IDEs that have css symbol lookup.
Conclusion
That’s what I’ve found so far organizing a small section of the UI over the last few weeks. What do you agree with? What needs adjustment? Reach out in the Responses below.
Thanks for reading.
— Lawrence Whiteside