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
❌ Wrong - Don't nest elements
✅ Correct - Flat structure
.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:
✅ Correct - Both classes
❌ Wrong - Modifier alone
< div class = "card card--featured" >
< h2 class = "card__title" > Title </ h2 >
</ div >
Real Examples from the Project
/* 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 : -4 px ;
right : -8 px ;
min-width : 18 px ;
height : 18 px ;
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
Traditional CSS - Conflicts
BEM - No Conflicts
/* File 1 */
.card .title {
font-size : 16 px ;
}
/* File 2 - Oops, this affects File 1's cards too! */
.card .title {
font-size : 20 px ;
}
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
Independent - Use Block
Dependent - Use Element
/* 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 ( 250 px , 1 fr ));
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
❌ Avoid Generic Names
✅ Be Specific
.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 ( 200 px , 1 fr ));
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 : 1 px ;
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
Pattern Syntax Example Block .block.headerElement .block__element.header__navModifier .block--modifier.header--darkElement Modifier .block__element--modifier.header__nav--mobile
Next Steps
Flexbox Apply BEM to flexible layouts
Variables Use CSS variables with BEM