Structuring CSS Effectively with BEM Methodology

Structuring CSS Effectively with BEM Methodology

  • Post Author:

I decided to write this blog post as part of my own learning. Before, I didn’t know there were structured methods like BEM for organizing CSS class names.  I used to just name styles based on personal preference. By writing about it, I was able to understand the concept more clearly.

The Block, Element, Modifier methodology or commonly referred to as BEM is a naming convention standard for CSS class names.

A BEM (Block Element Modifier) class name typically consists of three parts:

  1. Block – Represents the standalone component or the outermost parent element.
  2. Element – A part of the block that performs a specific function. Elements are always tied to their parent block.
  3. Modifier – A flag used to change the appearance, behavior, or state of a block or element.

When all three are combined, a BEM class name follows this format:

block__element--modifier

Key Goals of BEM:

  1. Modularity
    BEM encourages the development of independent, reusable components. Each block or element has its own styles, making it easy to isolate and reuse.
  2. Clarity & Readability
    The naming pattern (block__element--modifier) makes it immediately clear what each class is doing and how it fits into the UI structure.
  3. Avoids CSS Conflicts
    By using unique and structured class names, BEM reduces the chances of style conflicts and specificity wars.
  4. Scalability
    As a project grows, BEM’s consistent structure allows developers to scale the CSS without it becoming messy or unmanageable.
  5. Ease of Collaboration
    Teams can understand each other’s code faster because BEM provides a shared language for writing CSS.

By following BEM structured naming conventions, it can help create reusable components with predictable class names, making development faster and more consistent across different parts of application.

Example

CSS

.my-page {
  background-color: rgb(0,113,242);
  width: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: auto;
  padding: 1rem;
}

.my-page__title {
  font-size: 30px;
  font-weight: bold;
  margin-bottom: 8px;
  color: #fff;
}

.my-page__content  {
  font-size: 20px;
  color: #fff;
  text-align: center;

}

.my-page__content--highlighted {
  color: white;
  background-color: #555;
  padding: 0.5rem 1rem;
  border-radius: 5px;
}

HTML

<div class="my-page">
    <h3 class="my-page__title">My Page Title</h3>
    <p class="my-page__content">Lorem Ipsum has been the industry's standard dummy text ever since the
        <span class="my-page__content--highlighted">1500s</span>
        when an unknown printer took a galley of type and scrambled it to make a type specimen book.
    </p>
</div>

Issues I Faced / What Confused Me When Learning BEM

When I first learned about BEM, I faced a few challenges and points of confusion, but here’s how I overcame them:

  1. Long class names – At first, writing .block__element–modifier felt too long compared to using short class names.
    I reminded myself that clarity matters more than brevity. Long class names may look lengthy, but they reduce confusion and make the code easier to understand for other developers.
  2. Mixing BEM with my usual CSS style approach – Since I was used to writing all my styles in a single file and naming classes based on my preference, BEM initially felt restrictive.
    I started small by applying BEM to one component at a time, which helped me avoid feeling overwhelmed.
  3. Block vs. Element confusion – I wasn’t always sure if something should be considered a separate block or just an element inside another block.
    I followed a simple rule: if it can exist independently, it’s a block; if it depends on the block, it’s an element. This guideline helped me decide faster.
  4. Over-nesting – Sometimes I caught myself creating deep structures like .block__element__sub-element, which goes against the simplicity of BEM.
    I learned to introduce new blocks instead of over-nesting elements.
  5. When to use modifiers – Deciding whether to add a modifier or just use a utility/helper class was tricky.
    I overcame this by setting a simple rule: use modifiers when the variation is specific to the component, and use utility classes for more generic styling.

Alternative CSS Methodologies

Here are some of the other CSS methodologies that I’ve researched and learned so far.

Object-Oriented CSS (OOCSS)

Just like object-oriented programming, OOCSS (Object-Oriented CSS) focuses on creating reusable and modular CSS code. The core principle of OOCSS is the separation of structure and skin. Structure refers to the base styles that define the layout and positioning, while skin refers to the visual design aspects such as colors, backgrounds, and borders.

Example

CSS

/* Structure */
.button {
  display: inline-block;
  padding: 0.6rem 1.2rem;
  font-size: 1rem;
  font-weight: 600;
  border-radius: 6px;
  border: none;
  cursor: pointer;
}

/* Skin: submit button */
.btn-submit {
  background-color: #28a745;
  color: #fff;
}

/* Skin: cancel button */
.btn-cancel {
  background-color: #dc3545;
  color: #fff;
}

HTML

<button class="button btn-submit"> Submit </button>
<button class="button btn-cancel"> Cancel </button>

Scalable and Modular Architecture for CSS (SMACSS)

The concept of SMACSS is the separation of concern. It focuses on categorizing CSS rules into distinct types such as Base, Layout, Module, State, and Theme.

The SMACSS 5 categories: 

  1. Base – foundation  or the global of your style 
  2. Layout – structure or the skeleton of your style
  3. Module – reusable components
  4. State – temporary condition or the dynamic behavior 
  5. Theme – the styles for visual variations

Example

CSS

/* Base */
body {
  margin: 0;
  font-family: Arial, sans-serif;
}
a {
  text-decoration: none;
}

/* Layout */
.l-header {
  background: #0d0b0b;
  padding: 1rem;
}

.l-main {
  padding: 2rem;
}

/* Module */
.button {
  display: inline-block;
  padding: 0.5rem 1rem;
  border-radius: 4px;
  border: none;
  font-weight: bold;
  cursor: pointer;
}

.btn-primary {
  background: #007bff;
  color: white;
}

/* State */
.is-hidden {
  display: none;
}

.is-disabled {
  background: #ccc;
  cursor: not-allowed;
}

/* Theme */
.theme-dark {
  background: #222;
  color: #f0f0f0;
}

.theme-dark .btn-primary {
  background: #17a2b8;
}

HTML

<body class="theme-dark">
  <header class="l-header">
    <h1>Simple SMACSS Example</h1>
  </header>
  <main class="l-main">
    <button class="button btn-primary">Click Me</button>
    <button class="button is-disabled">Disabled</button>
  </main>
</body>

Atomic CSS (ACSS)

A CSS methodology where we create small, single-purpose utility classes, each applying exactly one styling property (such as padding, margin, text color, etc.). Instead of writing long CSS selectors for each component, we compose styles by combining these atomic classes directly in the HTML. Atomic CSS is the idea behind frameworks like TailwindCSS.

Example

CSS

/* Background */
.bg-light {
  background-color: #f5f5f5;
}

.bg-dark {
  background-color: #333;
}

/* Display */
.flex {
  display: flex;
}
        
.items-center {
  align-items: center;
}
        
.justify-between {
  justify-content: space-between;
}

/* Spacing */
.m-0 {
  margin: 0;
}
        
.mt-1 {
  margin-top: 0.25rem;
}

.mt-2 {
  margin-top: 0.5rem;
}
        
.p-2 {
  padding: 0.5rem;
}
        
.p-4 {
  padding: 1rem;
}

/* Text */
.text-center {
  text-align: center;
}
        
.text-bold {
  font-weight: bold;
}
        
.text-red {
  color: red;
}
 
.text-blue {
  color: blue;
}

HTML

<div class="p-4 bg-light">
 <h1 class="text-center text-blue text-bold mt-2">Atomic CSS</h1>
  <p class="mt-1 text-red">This paragraph uses atomic utility classes.</p>

  <div class="flex justify-between items-center mt-2">
    <button class="p-2 bg-dark">Button 1</button>
    <button class="p-2 bg-dark">Button 2</button>
  </div>
</div>

Inverted Triangle CSS (ITCSS)

The idea of ITCSS is to structure CSS in layers, starting from the most generic styles like resets and global variables at the top, down to the most specific styles like component and utility classes at the bottom. It’s called an inverted triangle because at the top, styles are broad, generic, and global and at the bottom, styles are narrow, specific, and explicit.

ITCSS often uses .scss (Sass) because:

  • The Tools layer (like mixins or functions) doesn’t exist in plain CSS.
  • It’s easier to organize multiple files using @import or @use.
  • It helps keep your code modular and clean.

Browsers don’t understand @mixin or @include. That’s why we use a Sass compiler to convert SCSS to CSS. Before deployment, we run a build tool like Vite, Laravel Mix, Webpack, or the Sass CLI that compiles .scss files into .css. Browser loads the compiled CSS, not the SCSS.

Example

/src/css
│
├── settings/_colors.scss
├── tools/_mixins.scss
├── generic/_reset.scss
├── elements/_headings.scss
├── objects/_container.scss
├── components/_card.scss
├── utilities/_text.scss
└── main.scss

settings/_colors.scss

:root {
  --color-primary: #007bff;
  --color-secondary: #6c757d;
}

tools/_mixins.scss

@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin rounded($radius) {
  border-radius: $radius;
}

generic/_reset.scss

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

elements/_headings.scss

h1 {
  font-size: 2rem;
  color: var(--color-primary);
}

objects/_container.scss

.container {
  width: 90%;
  margin: 0 auto;
  padding: 20px;
}

components/_card.scss

.card {
  background: #fff;
  border: 1px solid #ddd;
  padding: 16px;
  min-height: 120px;

  @include flex-center;
  @include rounded(10px);

  text-align: center;
  color: var(--color-primary);
  font-weight: bold;
}

utilities/_text.scss

.text-center {
  text-align: center;
}

.text-bold {
  font-weight: bold;
}

.mt-2 {
  margin-top: 0.5rem;
}

main.scss

@import "settings/colors";
@import "tools/mixins";
@import "generic/reset";
@import "elements/headings";
@import "objects/container";
@import "components/card";
@import "utilities/text";

HTML

<div class="container">
  <h1 class="text-center">ITCSS Example</h1>

  <div class="card text-bold mt-2">
    I am a Card Component <br>
    (styled with ITCSS layers)
  </div>
</div>

Comparison with Alternatives and My Preference

If I have to choose among the CSS methodologies, it really depends on the project scale.

For small to mid-sized projects,

I would go with a combination of Atomic CSS (using TailwindCSS) and BEM. Not all styling are covered by TailwindCSS, so BEM fills the gap for custom or complex styles that TailwindCSS can’t handle. For me, this combination is a balanced and solid approach.

For mid to larged-sized projects,

I would still use the combination of Atomic CSS (using TailwindCSS) and BEM, and I would also apply Inverted Triangle CSS (ITCSS). As the project grows, we will have multiple layers of CSS. ITCSS helps organized these layers logically from broad global styles to narrow component specific styles. Atomic CSS (using TailwindCSS) and BEM is a combination of balanced and solid approach. Adding Inverted Triangle CSS structured system for long-term growth.

Ultimately, there’s no one-size-fits-all solution. Choosing the right CSS methodology depends on what best suits the team’s workflow, the project’s needs, and its scale. In my opinion, the combination of Atomic CSS (TailwindCSS) and BEM is a solid choice for small to mid-sized projects. Adding ITCSS for larger projects makes the CSS architecture more organized and scalable.

we are hiring

優秀な技術者と一緒に、好きな場所で働きませんか

株式会社もばらぶでは、優秀で意欲に溢れる方を常に求めています。働く場所は自由、働く時間も柔軟に選択可能です。

現在、以下の職種を募集中です。ご興味のある方は、リンク先をご参照下さい。

コメントを残す