BEM Methodology with SCSS
Learn how to implement BEM (Block Element Modifier) methodology effectively using SCSS features.
BEM Basics
Understanding the core concepts of BEM: Blocks, Elements, and Modifiers.
// BEM Naming Convention
.block {} // Block
.block__element {} // Element
.block--modifier {} // Block Modifier
.block__element--modifier {} // Element Modifier
// Example with a card component
.card {} // Block
.card__header {} // Element
.card__content {} // Element
.card__footer {} // Element
.card--featured {} // Modifier
.card__header--highlighted {} // Element Modifier
HTML Usage:
<div class="card card--featured">
<div class="card__header card__header--highlighted">
<h2 class="card__title">Title</h2>
</div>
<div class="card__content">Content</div>
<div class="card__footer">Footer</div>
</div>
BEM with SCSS Nesting
Using SCSS nesting to write BEM in a more maintainable way.
// Traditional CSS
.button {}
.button__icon {}
.button__text {}
.button--primary {}
.button--primary__icon {}
// SCSS with nesting
.button {
// Block styles
display: inline-flex;
align-items: center;
padding: 0.5rem 1rem;
// Elements
&__icon {
margin-right: 0.5rem;
}
&__text {
font-weight: 500;
}
// Modifiers
&--primary {
background: blue;
color: white;
// Modifier-specific element styles
.button__icon {
// or use &__icon for better nesting
fill: white;
}
}
}
BEM Mixins
Creating reusable mixins for BEM patterns.
// BEM Mixins
@mixin block($block) {
.#{$block} {
@content;
}
}
@mixin element($element) {
&__#{$element} {
@content;
}
}
@mixin modifier($modifier) {
&--#{$modifier} {
@content;
}
}
// Usage
@include block('nav') {
display: flex;
@include element('item') {
padding: 1rem;
@include modifier('active') {
font-weight: bold;
}
}
@include modifier('vertical') {
flex-direction: column;
}
}
// Outputs
.nav {
display: flex;
}
.nav__item {
padding: 1rem;
}
.nav__item--active {
font-weight: bold;
}
.nav--vertical {
flex-direction: column;
}
Complex Components
Handling complex components with nested elements and modifiers.
// Complex form component
.form {
&__group {
margin-bottom: 1rem;
&--error {
.form__label {
color: red;
}
.form__input {
border-color: red;
}
}
}
&__label {
display: block;
margin-bottom: 0.5rem;
&--required {
&::after {
content: "*";
color: red;
}
}
}
&__input {
width: 100%;
padding: 0.5rem;
&--large {
padding: 1rem;
}
&--error {
border-color: red;
}
}
&--inline {
.form__group {
display: flex;
align-items: center;
}
.form__label {
margin-bottom: 0;
margin-right: 1rem;
}
}
}
HTML Usage:
<form class="form form--inline">
<div class="form__group form__group--error">
<label class="form__label form__label--required">
Username
</label>
<input class="form__input form__input--large">
</div>
</form>
Context and Dependency Management
Handling component context and dependencies while maintaining BEM principles.
// Managing context
.article {
&__header {
margin-bottom: 2rem;
}
// Context-based styling
.button {
margin-right: 1rem;
&:last-child {
margin-right: 0;
}
}
}
// Component dependencies
.modal {
&__content {
.form {
margin-bottom: 0; // Override default form margin
}
}
}
// Theme variations
.theme-dark {
.button {
&--primary {
background: lighten($primary-color, 10%);
}
}
}
BEM Best Practices
Naming Conventions
- Use meaningful and clear names for blocks
- Keep element and modifier names concise
- Use double underscores for elements (__)
- Use double hyphens for modifiers (--)
- Avoid excessive nesting of elements
Structure
- Keep blocks independent and self-contained
- Avoid deep nesting of elements (max 2 levels)
- Use mixins for repeated patterns
- Maintain a flat structure where possible
Modifiers
- Use boolean modifiers when appropriate (--disabled, --active)
- Use key-value modifiers for variants (--color-primary, --size-large)
- Keep modifier names consistent across components
- Avoid modifier-only classes without their block class