I'm trying to pickup and understand the reasoning behind CSS naming conventions such as BEM or SUITCss. I'm having a hard time understanding the value of descendent class names in the presence of SCSS.
For example:
<ul class="menu">
<li class="menu__item"></li>
<li class="menu__item"></li>
<li class="menu__item">
<a href="#" class="menu__item_link">link</a>
</li>
</ul>
.menu {
.menu__item {
//styles
.menu__item__link { //styles }
}
//or alternatively this syntax..
&__item { //styles }
}
With the ability to nest rules in SCSS, I don't see the compelling reasons for me to include the ancestor class names in my code. Above I have defined styles that should only be used for an "item" that is inside of a "menu", using descendant class names. However, the nested structure already communicates this! The rules for menu__item would only apply to an item under a menu anyway, so why do I need include that in the class name?
Why not:
<ul class="menu">
<li class="item"></li>
</ul>
.menu {
.item {//styles}
}
I understand that the descendant naming convention is more explicit and perhaps more future friendly. I argue, however, that it is only more explicit in the html. If I wanted to consult how to build this "menu" module, I could just consult the CSS and see just as clearly how a menu has items nested inside.
I guess one possible advantage is that I could write my css un-nested, like so:
.menu { //styles }
.menu__item { //styles }
.menu__item__link { //styles }
And then use a "menu__item" anywhere and it would still be explicit in the class name that this was the styling of an item under a menu..but then why define it as a descendant of a menu at all then? (Another advantage, I suppose, is shorter CSS identifier strings if things aren't nested)
It seems to me that if a class name is to be used as a descendant under another, then nesting in SCSS achieves this and presents that logic clearly. Why would this BEM syntax be necessary then?
I'd like to hear someone explain the reasoning of this type of convention. I want to adhere to so called best practices, but it's hard for me to do so blindly without fulling understanding a convention.
CSS class is formed as block's or element's name plus two dashes: . block--mod or . block__elem--mod and . block--color-black with .
BEM stands for Block, Element, and Modifier. It's a CSS naming convention for writing cleaner and more readable CSS classes. BEM also aims to write independent CSS blocks in order to reuse them later in your project.
BEM stands for block, element, and modifier. It's a naming convention that divides the user interface into small, reusable components that will prepare us for the changes in design of our websites. This convention also enhances the cross-site copy/paste feature by helping make elements reusable components.
Several remarks.
1/ First,
.menu {
.menu__item { /* ... */ }
//or alternatively this syntax..
&__item { /* ... */ }
}
The two SCSS syntaxes are not equivalent. The first one uses a cascade (".menu .menu__item"), not the second one (".menu__item"). Only the second one is BEM compliant.
2/ Why not a cascade:
.menu {
.item { /* styles */ }
}
BEM allows scalability. When we write CSS, we focus only on one small context: the block. And each block can be reused many times.
But cascades are not context-free. In your example, there is a block "menu" that contains an element "item". The context of the element "item" is the block "menu". But the cascade breaks the context separation for the sub-blocks. A prefixed BEM syntax allows nesting blocks, the cascade doesn't. For example:
<ul class="menu">
<li class="menu__item"></li>
<li class="menu__item">
<div class="other-block">
<span class="other-block__item"></span>
</div>
</li>
</ul>
Notice the element "item" in the sub-block. With a cascade instead of a prefix, it would be styled by a rule that would target the elements "item" of the parent block.
3/ This class name is not BEM compliant:
.menu__item__link { /* styles */ }
Elements don't provide any context. Only blocks provide contexts. The context of a an element is the context of its block. So, "link" is not a descendant of "item" in the BEM tree. The two are brothers, independently of their situations in the DOM tree. You should use:
.menu { /* styles */ }
.menu__item { /* styles */ }
.menu__link { /* styles */ }
Lets start with idea of BEM or SMACSS.
The main task any methodology resolves is structuring and modularize your code.
For example BEM use following abstractions:
Block - independent part of UI (like feedback form),
Element - part of block cant exist without block (like feedback form button),
Modificator - helper that let you modify block or element ( like make button bigger or smaller).
SMACSS use different abstractions : Module, Layout, Base, State, Theme. To clearly got the idea, imagine your html page contains from logic layers,
1) BASE - you add css resets, define H1, H2 ... font sizes, define colors. So in base you put things than should be changed.
2) LAYOUT - adds grids, or separate page in regions. 3) Module - independent content item
3) STATE - very close to BEM modificator but connected with some action with module, like is_hided, is_collapsed
4) Theme - may be used for BASE override.
So to separate this abstractions you have to follow some naming convention , so you could from first look understand what does this class do. If you follow naming convention its also much easier to maintain you project6 its easily to explain new team members how code organized and how to write new code that looks like written by one person.
Its extremely important in large scale projects with large teams.
Plus, naming convention helps you to decrease number of descendant selectors, that improve performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With