Skip to main content

What is BEM?

BEM (Block Element Modifier) is a naming convention for CSS classes that makes your code:
  • More readable - Clear component structure
  • More maintainable - Easy to find and update styles
  • Less conflicting - Avoids specificity issues
  • More reusable - Components are self-contained

BEM Structure

.block { }                    ← Component
.block__element { }           ← Part of component  
.block--modifier { }          ← Variation of component
.block__element--modifier { } ← Variation of element

Separators

  • __ (double underscore) - Separates block from element
  • -- (double dash) - Separates element/block from modifier

Block (Component)

A standalone, independent component.
.header { }        /* Header component */
.card { }          /* Card component */
.button { }        /* Button component */
.product-card { }  /* Product card component */
Blocks should be independent and reusable anywhere on the page.

Element (Part of Block)

A part of a block that has no standalone meaning.
.card { }              /* Block */
.card__title { }       /* Element: title of the card */
.card__image { }       /* Element: image in the card */
.card__button { }      /* Element: button in the card */

Rule: No Nested Elements

.card__header__title { }  /* BAD - Too nested */
Never chain elements like .block__element1__element2. Always use .block__element regardless of nesting depth.

Modifier (Variation)

A flag that changes appearance or behavior.
.card { }                  /* Base card */
.card--featured { }        /* Featured variation */
.card--large { }           /* Large variation */
.card__title--bold { }     /* Bold title variation */

Using Modifiers in HTML

Modifiers are used together with the base class:
<div class="card card--featured">
  <h2 class="card__title">Title</h2>
</div>

Real Examples from the Project

Header Component

/* BLOCK: Header */
.header { }

/* ELEMENTS of header */
.header__container { }      /* Main container */
.header__logo { }           /* Logo area */
.header__logo-link { }      /* Logo link */
.header__logo-text { }      /* Logo text */
.header__logo-subtitle { }  /* Logo subtitle */
.header__search { }         /* Search area */
.header__search-form { }    /* Search form */
.header__search-input { }   /* Search input */
.header__search-button { }  /* Search button */
.header__nav { }            /* Navigation */
.header__nav-list { }       /* Nav list */
.header__nav-link { }       /* Nav link */
.header__categories { }     /* Categories bar */

/* MODIFIER: Cart link variation */
.header__nav-link--cart { }
HTML structure:
<header class="header">
  <div class="header__container">
    <div class="header__logo">
      <a href="/" class="header__logo-link">
        <span class="header__logo-text">MiTienda</span>
      </a>
    </div>
    
    <div class="header__search">
      <form class="header__search-form">
        <input type="text" class="header__search-input" />
        <button class="header__search-button">Search</button>
      </form>
    </div>
    
    <nav class="header__nav">
      <ul class="header__nav-list">
        <li><a href="#" class="header__nav-link">Home</a></li>
        <li><a href="#" class="header__nav-link header__nav-link--cart">Cart</a></li>
      </ul>
    </nav>
  </div>
</header>

Product Card Component

/* BLOCK */
.product-card { }

/* ELEMENTS */
.product-card__figure { }
.product-card__image { }
.product-card__content { }
.product-card__category { }
.product-card__title { }
.product-card__price { }
.product-card__shipping { }
.product-card__btn { }

/* MODIFIERS (if needed) */
.product-card--featured { }
.product-card--sale { }
HTML structure:
<article class="product-card">
  <figure class="product-card__figure">
    <img src="..." class="product-card__image" />
  </figure>
  <div class="product-card__content">
    <span class="product-card__category">Electronics</span>
    <h3 class="product-card__title">Product Name</h3>
    <p class="product-card__price">$99.99</p>
    <button class="product-card__btn">Add to Cart</button>
  </div>
</article>

Cart Badge with Modifier

/* Base nav link */
.header__nav-link {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs) var(--spacing-sm);
  color: var(--color-gray-600);
  transition: background-color var(--transition-fast);
}

.header__nav-link:hover {
  background-color: rgba(0, 0, 0, 0.05);
}

/* MODIFIER: Cart link gets position relative for badge */
.header__nav-link--cart {
  position: relative;
}

/* Badge counter using ::after pseudo-element */
.header__nav-link--cart[data-cart-count]:not([data-cart-count="0"])::after {
  content: attr(data-cart-count);
  position: absolute;
  top: -4px;
  right: -8px;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--spacing-xs);
  background-color: var(--color-error);
  color: var(--color-white);
  font-size: var(--font-size-xs);
  border-radius: var(--border-radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
}
HTML:
<a href="#cart" 
   class="header__nav-link header__nav-link--cart" 
   data-cart-count="3">
  Cart
</a>

BEM Benefits in Action

1. Self-Documenting

Just by reading the class name, you know:
.product-card__image
/* ↑ This is the image element inside the product-card block */

.header__nav-link--cart
/* ↑ This is a cart variation of nav-link inside header */

2. Low Specificity

/* BEM - specificity (0,0,1,0) */
.header__nav-link { }

/* Traditional nested - specificity (0,0,3,0) */
.header .nav .link { }
Lower specificity = easier to override when needed.

3. No Cascading Issues

/* File 1 */
.card .title {
  font-size: 16px;
}

/* File 2 - Oops, this affects File 1's cards too! */
.card .title {
  font-size: 20px;
}

4. Easy to Find Styles

HTML:
<button class="product-card__btn">Add to Cart</button>
You know exactly what to search for in CSS:
.product-card__btn { /* Found it! */ }

Common Patterns

Boolean Modifiers

.button { }               /* Default state */
.button--active { }       /* Active state */
.button--disabled { }     /* Disabled state */
.button--loading { }      /* Loading state */
<button class="button button--active">Active</button>
<button class="button button--disabled">Disabled</button>

Value Modifiers

.button { }               /* Base */
.button--primary { }      /* Primary color */
.button--secondary { }    /* Secondary color */
.button--small { }        /* Small size */
.button--large { }        /* Large size */
<button class="button button--primary button--large">Primary Large</button>
<button class="button button--secondary button--small">Secondary Small</button>

State Modifiers

.card { }
.card--featured { }       /* Featured card */
.card--sale { }           /* On sale */
.card--sold-out { }       /* Sold out */

When to Use Block vs Element

Use Block if it can be used independently
Use Element if it only makes sense inside a block
/* Button can be used anywhere */
.button { }

/* Can use it in header, footer, cards, etc. */

BEM with Flexbox/Grid

/* Grid container is a block */
.benefits__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--spacing-lg);
}

/* Grid items are elements */
.benefits__item {
  background-color: var(--color-gray-100);
  padding: var(--spacing-lg);
  border-radius: var(--border-radius-md);
}

.benefits__icon { }
.benefits__item-title { }
.benefits__item-text { }

BEM Naming Conventions

Use Descriptive Names

.header__item { }    /* Which item? */
.card__text { }      /* Which text? */

Multi-Word Names

Use single dash for multi-word blocks/elements:
.product-card { }              /* Block */
.product-card__price-tag { }   /* Element */
.product-card--on-sale { }     /* Modifier */

BEM Anti-Patterns

❌ Don’t Over-Nest

/* BAD - Too specific to HTML structure */
.header__nav__list__item__link { }

/* GOOD - Flat BEM */
.header__nav-link { }

❌ Don’t Mix BEM with Nested Selectors

/* BAD - Defeats the purpose */
.header .header__nav-link { }

/* GOOD - Just use the class */
.header__nav-link { }

❌ Don’t Use ID Selectors

/* BAD - IDs have too high specificity */
#header { }

/* GOOD - Use classes */
.header { }
/* BLOCK */
.footer { 
  background-color: var(--color-white);
  padding: var(--spacing-2xl) var(--spacing-lg);
}

/* ELEMENTS */
.footer__container { 
  max-width: var(--container-max-width);
  margin: 0 auto;
}

.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-xl);
}

.footer__column-title {
  font-weight: 600;
  margin-bottom: var(--spacing-md);
}

.footer__links {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.footer__link {
  color: var(--color-gray-500);
  transition: color var(--transition-fast);
}

.footer__link:hover {
  color: var(--color-secondary);
}

.footer__divider {
  border: none;
  height: 1px;
  background-color: var(--color-gray-200);
  margin: var(--spacing-lg) 0;
}

.footer__bottom {
  display: flex;
  justify-content: space-between;
}

.footer__copyright { }
.footer__legal { }

Quick Reference

PatternSyntaxExample
Block.block.header
Element.block__element.header__nav
Modifier.block--modifier.header--dark
Element Modifier.block__element--modifier.header__nav--mobile

Next Steps

Flexbox

Apply BEM to flexible layouts

Variables

Use CSS variables with BEM

Build docs developers (and LLMs) love