This blog post discusses a possible direction for allocating CSS class names in HTML markup. It briefly describes the current rules, then moves on to a proposal around the adoption of BEM (or a variant thereof).
This relates to community work going on (led by SNOW.DOG) around exploring a Sass port of the Magento 2 UI Library, currently written in Less files. (I recently blogged on possible conventions around using Sass in Magento 2.) Adding support for Sass is an opportune time to review the current CSS class names in use – it is better to make any changes now for the Sass port to leverage.
Please note, the primary purpose of this blog post is to collect community feedback, particularly from frontend developers. Is the addition of BEM styled class names a benefit, or just “another set of class names to try and understand”? (Disclaimer: This blog post is not a commitment when or even if this work will be done.)
The current documented guidance for CSS class names in Magento 2 is to use semantic class names, not presentation oriented. The documentation currently does not go much further than that. (There are additional rules the core team is currently using which has not yet made it to the documentation.)
Magento 2 brought many of the PHTML files, and hence CSS class names, over from Magento 1. Many of the old names were good semantic names and so purposely kept. Others class names were retained because the effort to review and improve them (ensuring that nothing was broken in the process) was not considered worth the benefit. Work has been underway to incrementally introduce a more consistent approach to CSS class naming. You may notice new CSS class names starting with “.block-” and similar. Such names are effectively a second generation of class names being introduced over time. These new class names however have not been pushed out consistently through all PHTML files.
Regardless, there is still general confusion around selector specificity to use. For example, currently you may have a CSS selector such as
.product .image > .header .info .extra._active
(Okay, this might be an extreme example, but it makes a point.) In BEM, this may become
It is much clearer from the name when the CSS selector is appropriate. And there is less confusion over which class names to use in combination for the selector. A part of the thoughts behind BEM is combinations of multiple class names in a selector can actually be an anti-pattern in large projects. It takes a lot of discipline to get right. Better is to have more specific class names and use technologies such as Less and Sass to manage the CSS definitions better.
Asking the Community
Bartek (from SNOW.DOG) held a community vote in the forums some time back. 33 people voted, with the top votes being:
- BEM – 16 votes
- OOCSS – 4 votes
- SMACSS – 4 votes
- Any aka YOLOCSS – 3 votes
- Atomic Design – 2 votes
Everything else had 1 or less votes.
Let’s look a bit deeper into OOCSS, SMACSS, and BEM. I found this blog post by Matt Stauffer particularly useful. My super quick summary is as follows.
OOCSS (Object-oriented CSS) talks about concepts like “components” that can be used on different pages. The idea is to encourage “always encode a panel like this if it is meant to look the same across the site”. Think about what to include in the CSS, and what to exclude. Design it and document it so people know the rules.
SMACSS (Scalable and Modular Architecture for CSS) talks about categories of CSS rules: base (raw HTML elements), layout (like Magento page layouts – header, footer, sidebar), modules (like Magento blocks), state rules (e.g. “.is-expanded”), and themes (not needed by Magento).
BEM then goes on as one concrete way to apply the above two guidelines – recommending using a “Block name” to scope “Elements” in the block, with “Modifiers”, hence the name “Block-Element-Modifier” (BEM). (Note that “block” here is a BEM concept, not the Magento concept of a block.) The BEM block has a name, with nested elements using double underscore to separate block and element name (e.g. the block “product-info” may contain a CSS class name of “product-info__active”), and double hyphen for optional modifiers (e.g. “product-info__extra–active”).
Since BEM follows the OOCSS guidelines, and we would adopt the SMACSS concepts as well, a CSS class naming scheme adapting all of these options actually has received 24 out of 33 votes. Pretty dominant.
The following is a skeleton proposal for how to move forward with CSS class naming in Magento 2. This is not intended to be a definitive proposal, but rather provide enough information as a vehicle to gather support (or lack thereof) from the frontend developer community.
The proposal is based around adding new CSS class names (deprecating old names sometime in the future). As such, the PHTML files are not going to become shorter with this proposal. Rather new, longer class names are going to be added to the PHTML files on top of the existing class names.
(There are thoughts around deprecating the old class names over time, but that is not relevant to this discussion, so I am going to avoid the distraction of describing here.)
It is also proposed to continue to only rely on CSS class names, not ids. This is the current Magento 2 rule, and it is proposed to preserve this rule.
It is being considered whether to document all class names that are officially blessed BEM block names. The reason for this is “product-info” is both a valid “old form” name and a valid BEM name (for referring to the root element of the HTML), making it hard to determine which names are “old names” in some cases. Building up a registry of “approved/deprecated” names (maybe as a JSON or XML file on GitHub) would help developers know which class names to use or avoid.
I personally am not a frontend developer by trade. So his is my perspective on BEM et al. The idea is to introducing scoping in a way that makes sense with Magento 2. The BEM block names are really identifying well defined scopes. For example, each Magento 2 block generally has a PHTML file and would be allocated its own BEM block name.
For Magento, instead of using the SMACSS concepts of base, layout, modules, state rules, and themes, Magento concepts will be used instead. For example, page layouts will also be used as a BEM block (scoping rule for elements within the page layout).
The different levels of CSS rule specifications are as follows.
Base (HTML Elements)
Styling on raw HTML elements (no class names required) would be provided by Magento. No-one else should change such base rules. If someone wants to make changes, they should use a CSS class name. The risk of unexpected side effects is too great if a theme or similar changes the base HTML element style rules.
Standard class names are already defined by Magento for “header”, “footer”, “main”, “sidebar-main”, and “sidebar-additional”. These names could remain as BEM blocks, or class names such as “page-layout__header” could be introduced. (This is an example of decisions that would need to be made when introducing BEM – what are logical BEM blocks or scopes worthy of introducing a new root CSS class name.)
There would need to be review in some cases where multiple class names are provided, such as “sidebar sidebar-main” and “sidebar sidebar-additional”. Decisions are required to work out when CSS class names should be used versus Sass (or Less) mixins to avoid duplication.
Modules vs Blocks, Containers, and UI Components
Assuming each Magento block (and container) defines a new scope, the root of each such scope is allocated a unique name. (For vendors other than Magento, it is recommended to add a vendor name prefix to the block name to avoid accidental collections in block names.) Nested elements within the block all share root block prefix.
Magento UI Library Patterns
Magento UI Library Patterns also define new scopes. Examples may include buttons, grids, and forms. These concepts should appear the same across the site.
This post contains a quick introduction on how BEM could be adopted by Magento 2. This post is to get any feedback on whether the benefits of introducing new CSS class names following BEM is greater than the potential confusion of introducing yet another set of CSS class names.
If there is general community support (particularly from the frontend developer segment of the developer base), the next steps would be to refine the proposal and then investigate how to adopt it.