BEM (Block Element Modifier) stands as a widely embraced CSS class naming convention designed to simplify the maintenance of cascading style sheets. Recognized for its effectiveness in organizing code and promoting reusability, BEM plays a crucial role in enhancing the clarity and structure of CSS. In the following discussion, we assume a foundational understanding of the BEM naming convention, directing our focus towards refining its syntax and addressing potential challenges. As we delve into the nuances of BEM, we introduce an alternative approach—ABEM (Atomic Block Element Modifier)—which seeks to overcome certain limitations while aligning with the principles of Atomic Design.
The standard BEM syntax is: “block-name__element-name–modifier-name”. Breaking styles into small components facilitates easier maintenance compared to dealing with high specificity scattered across the stylesheet. However, the syntax poses challenges in production and may cause confusion for developers. This article introduces a refined version of the syntax named ABEM (Atomic Block Element Modifier):
An Atomic Design Prefix
The prefix “a/m/o” belongs to Atomic Design methodology and should not be confused with Atomic CSS, as they are distinct concepts. Atomic Design is a structured approach aimed at efficiently organizing components to enhance code reusability.
It splits the components into three folders: atoms, molecules, and organisms. Atoms represent basic components, often comprising only one element such as a button. Molecules are comprised of small clusters of elements or components, like a form field with a label and input. Organisms, on the other hand, are intricate components composed of multiple molecules and atoms, for example, a comprehensive registration form.
Utilizing Atomic Design alongside classic BEM presents a challenge due to the absence of clear indicators indicating the type of component a block represents. This lack of clarity can lead to difficulty in locating the code for a particular component, often requiring searches across multiple folders. By prefixing with “atomic,” it becomes instantly evident which folder houses the component, streamlining the navigation process.
In Classic BEM, each word within a section is separated by a single dash. It’s worth noting that in the example provided, the atomic prefix is also set apart from the remainder of the class name by a dash. Consider the implications when adding an atomic prefix to Classic BEM versus camelCase:
At first glance, the component name appears as “o subscribe form” in the Classic BEM method, where the significance of the “o” is obscured. However, in the camelCase version, adding “o-” distinctly separates this prefix, indicating its intentional distinction from the component name. Alternatively, in Classic BEM, one could apply the atomic prefix by capitalizing the “o” as follows:
While capitalizing the “o” in Classic BEM would address the problem of it blending into the class name, it doesn’t resolve the fundamental issue inherent in the classic BEM syntax. When words are separated by dashes, the dash character loses its utility as a means of grouping. Employing camelCase allows us to reserve the dash character for supplementary grouping, such as appending a number to the end of a class name. Additionally, camelCase enhances the clarity of class name grouping, simplifying processing. In camelCase, each break in the class name signifies a distinct grouping, whereas in classic BEM, such breaks can indicate either a grouping or simply a space between words within the same group.
Consider this silhouette of a classic BEM class (with an atomic prefix) and attempt to discern the delineation between the prefix, block, element, and modifier sections:
Now, take a look at this version. It’s identical to the one above, but this time it employs camelCase to separate each word instead of dashes:
These silhouettes represent how your mind visually parses through your code. The surplus of dashes in the class name diminishes the clarity of groupings. While reading the code, your brain must discern whether encountered gaps signify new groupings or merely separate words within the same group. This ambiguity increases cognitive load and complicates the task at hand.
Using Multi-class Selectors (responsibly)
A fundamental principle of BEM is that each selector should comprise only one class. This practice aims to maintain CSS code by ensuring that selector specificity remains low and easily manageable. On the one hand, low specificity is preferable over having specificity run rampant. Conversely, adhering strictly to a one-class per selector rule might not always be the optimal approach for projects. Introducing some multi-class selectors into our styles can actually enhance maintainability rather than detract from it.
The presence of higher specificity declarations doesn’t necessarily translate to increased complexity in maintaining our CSS. When employed judiciously, assigning higher specificity to certain rules can actually streamline CSS maintenance. The essential aspect of crafting maintainable CSS with varying specificity levels is to intentionally increase specificity, rather than doing so merely because an element happens to be nested within another.
The separation of the modifier results in cleaner HTML.
This is the most significant alteration introduced by ABEM syntax. Rather than appending the modifier directly to the element class, it is applied as a distinct class.
One of the primary grievances voiced by almost everyone when initially learning BEM is its perceived ugliness, particularly concerning modifiers. Consider this example, which only incorporates three modifiers yet appears chaotic:
The repetition makes it difficult to read what it is trying to do. Now look at this ABEM example that has all the same modifiers as the previous example:
It is much cleaner. It’s significantly clearer to grasp the intent behind those modifier classes without the clutter of repetitive elements obstructing the view.
Even when examining an element with browser DevTools, the complete rule is still visible in the styling panel, thereby preserving the link to the original component in that regard.
It’s not much different to the BEM equivalent.
ABEM modifier technique summary
To maximize the effectiveness of the ABEM modifier, default to using the “.-modifierName” or “&.-modifierName” syntax, depending on which element bears the class.
Resort to direct targeting if nesting a component within itself poses difficulties.
In case of shared modifier name collisions, incorporate the component name into the modifier.
The BEM naming convention methodology enables breaking down CSS into small, easily manageable components, steering clear of unwieldy, high-specificity code that’s hard to maintain. However, the official BEM syntax leaves much to be desired.
The official BEM syntax falls short in several aspects:
- It lacks support for Atomic Design.
- Extending it isn’t straightforward.
- Processing the grouping of class names takes longer.
- Managing state on large components is challenging.
- It tends to prioritize single-class selectors over double-class selectors, despite the latter often offering easier maintainability.
- Overuse of name spacing can cause more issues than it solves.
- Proper implementation can result in bloated HTML.
The ABEM approach offers several advantages:
- Facilitates working with Atomic Design by providing a more compatible syntax.
- Utilizes the dash character for additional grouping, enhancing clarity.
- Enables quicker processing of class name groupings.
- Effectively manages state on components of any size, regardless of subcomponents.
- Promotes controlled specificity to mitigate team confusion and enhance site maintainability.
- Minimizes unnecessary name spacing.
- Maintains clean HTML with minimal additional classes applied to modules, while preserving BEM’s benefits.