Lately, I’ve been tossing around the relevance of CSS as I had learned it. That is creating a style sheet, linking that sheet to a file, and target your elements using broad strokes first and then specificity for everything else. It was recommended to me that my stylesheet selectors be listed in order of specificity, that is with the broader strokes like a body selector on top and the finer details like a selector targeting an anchor tag nested in a list at the bottom.
Recently, I attempted to use those principles on a React project. I quickly ended up running into specificity issues. As I started importing components into my app components, my styles began to overlap. I remember thinking to myself, “There has to be an easier way.” There was.
Initially, I began my search by looking for a better way to write CSS. A conventional way of writing styles in my React app. Eventually, I came across BEM (Block Element Modifier).
The first part of this methodology is to only use class names. This will resolve specificity conflicts and keep your code robust (nested selectors make your code brittle). This part of the methodology could be called styles isolation.
This can also describe the block and element parts of BEM. Each component or part of a component exists within a box and elements exist within those boxes. So elements cannot exist outside of a box. Each box class name should clearly describe the component's purpose and the class name of the elements within that box should be named after the box that contains it.
The second part of BEM is mixins and modifiers. If, for example, two similar forms with similar functionality exist within a component and they need to be styled differently, they can both use the universal form class name but one can have an additional modifier class name which both describes the difference in that form and alters the style. Mixins work similarly in that now if you need to make a different form, you can use the universal form style and then add an additional class that describes a different kind of form and that will then be the universal model for that form.
The third part of BEM is that each block will have its own folder and each technology will have its own file. This includes block modifiers. This file structure makes it easy to not only move the blocks to other projects but to also only include the parts of that block that you need on that project. Each file should follow the same BEM naming conventions as the class names.
To reiterate, BEM is just one convention of using CSS. One that removes a lot of the drawbacks developers are pitted against when working with stylesheets. It replaces issues with CSS not being reusable across components, keeps your styles DRY (non-repetitive), and stops specificity issues which tend to make your code very brittle and hard to scale. It takes all those issues with CSS and trades them for putting class names on everything you want to be styled having descriptive class names which may sometimes get quite long. You can even use this convention with other technologies as well.
I know there’s a lot to BEM but lucky for us, most CSS libraries and tools are designed around convention already. One of which allows you to take it a step further to make your elements into components.
‘Styled Components’ allow you to put your CSS in JS files using template literals and then import those components into your project. You don’t even need to give your components a class name. Styled components, behind the scenes, is giving all your styled components their own unique class names.
The drawback here is that the unique class names have nothing to do with the actual components themselves making it harder to track down errors.
So, with styled-components, you are adding very little overhead to bake in that CSS convention for you.
This leads me to CSS libraries. Yet again, a step further. Where styled-components allow us the ability to put CSS styles into components which essentially bake convention into your app’s styles, CSS libraries are a collection of premade components you can use as-is or modify to your liking. They follow the same convention and allow you to get a project off the ground in very little time. The downside with libraries is that often library components will have more than you need and that could end up bloating your app as it grows. Also, the longer you rely on a library, the more you increase your app’s dependency on that library.
I’m sure you may have noticed a pattern here, starting from CSS convention, moving to a tool that implements that convention, and then finally to a library that creates the components for you.
Which is best depends on your situation.
I tend to use a combination of all three on my projects and how much of each I utilize depends on the level of detail and functionality I am looking for on my project.
Sometimes you need to get a project up and running quickly, in this case, it would be a simple matter to use a CSS library. Sometimes though, your design needs will be too much for a library to predict and you’ll need to create your own components.
Let me know what you think, I’m also interested in hearing what your workflow is like. If you could only know the excitement I felt when I discovered Styled Components, I’m always on the lookout for useful tools.
https://www.smashingmagazine.com/2019/06/styling-modern-web-apps/ — (Goes over BEM, Preprocessors, and design systems (so kinda like libraries))
https://styled-components.com/ — Styled Components
https://bit.dev/ — (Open source design system (Create and upload components or find and download components. The components are usually grouped together by creators -> style))