FE, CSS, BEM, ITCSS, WC, WTF!?
There is a huge stack to take into account if you want to use the latest tools in your projects. It’s easy to get lost, don’t know if you’re up-to-date, or if you are missing something. What I want with this post is to share some of the things that are being used here in Worldsensing by the Front End department. Sharing can be a good way to show anyone the way we work, receive feedback, and think about what we are doing but also where do we want to go next.
I’m going to talk through different topics we are currently using, some of them still investigating and quite new, but worth mentioning:
Naming convention
BEM stands for Block Element Modifier and it is a naming standard.
Since we work with components we want to have an according way to name them. We need a hierarchy while defining the markup, but avoid nesting while defining how this markup will look like. This means an easy way to see parents and children in HTML and less specificity when writing our CSS.
A BEM class looks like .Block__Element--Modifier
so in plain HTML:
<div class="menu menu--enabled">
<div class="menu__button">Home</div>
</div>
To me, one disadvantage while writting in JSX is that if we want to use a modifier, we can’t use the double hyphen without using the square brackets.
<div className={[css.menu, css[‘menu--enabled’]].join(‘ ‘)}>
<div className={css.menu__button}>Home</div>
</div>
Now that we don’t have nesting but hierarchy, it’s time to take the advantage of it. The clue of BEM is that we don’t need to nest, so if we do it we are wasting a powerful weapon.
.menu{}
.menu__button{}
.menu--enabled{}
For those using tools like SASS, don’t forget to think about what the compilation will look like. For instance, if we nest our elements and modifiers with an ampersand it will compile into the previous example, but if we interpolate the ampersand like #{&}__button
it will compile to a nested menu button class. Knowing this, we can use it like so:
.menu{
&__button{}
&--enabled{}
&#{&}--enabled &__button{}
}
compiles to:
.menu {}
.menu__button {}
.menu--enabled {}
.menu.menu--enabled .menu__button {}
Global scope
We use ITCSS which means Inverted Triangle CSS and it’s a concept promoted by Harry Roberts. The key mission is to avoid unnecessary overwriting by going from the most global level of our elements to the most concrete one. That’s why is called inverted triangle.
There are some predefined levels to get all the code approached into them, but since this is just an orientation you can adapt this levels to your needs, we have it like:
1. Settings: variables of colors, measures, etc.
2. Tools: mixins and functions.
3. Generic: *, html, body and pseudo-selectors. First output to css.
4. Base: all kind of HTML tags. Place for normalizers.
5. Objects: definition of objects. First time classes are used.
6. Components: definition of components extending from objects.
This is just an example and since is not strict can be modified. This is a good approach if you want to keep everything tidy. You can add third libraries and place them to the according level. Configure the levels to your needs.
Local scope
ITCSS is very useful in global styling, but if we want to define our components locally—and we do—we can’t use Components globally like ITCSS does. In my case, we are using this Components folder to refactor some components already done in the project, but the idea is to finally remove it.
Local scope can produce duplicate conflicts but CSS modules solve this problem. CSS modules give a unique name to each class by adding a hash to it. You can set this by changing the localIdentName. We’re currently using [name]__[local]___[hash:base64:5]
. So for example, menu__item
class name is no longer just local but contexted and hashed, like: menu__menu__item___2m5dR
.
If we want to make an exception and define a class like global it is possible with the :global()
wrap. It will compile the class name like it is.
CSS modules brings a way to reuse other css used in other components that are now separated from the rest by its hashed and unique styling. It’s called composes
and works like an extend in SASS.
It is also possible to share variables between SASS and JS with the :export{}
method. We are using it with colors we need to pass, for example.
Future steps
We are breaking our code into components that are separated one from the other. We want these components to be independent. So our the next step is converting reusable components to Web Components.
Web components are custom elements that can be reused like HTML tags. So you can create <custom-tag/>
.
Web Components can be encapsulated, this is called Shadow DOM, it hides markup therefore it can’t be reached unless it is declared. Some of the already known HTML elements have this attribute, like input, video, iframe, etc.
Like CSS modules, Web components have some functionalities like :host()
that enable the communication between components even when they are encapsullated.
Today Web Components have the support of most of the main browsers, and also great community contribution.
As I said, it is important to think about what’s next and where we can improve. We are always trying to improve by using new technologies and approaches. It doesn’t always work, but when it does it’s really worth it. It is important to keep trying.
These are some of the things we use. I hope this can be helpful and you enjoyed it. Comments and feedback is more than welcome.