When you’re building websites for real-world use (whether it’s a brochure site or a complex web app) clean, scalable CSS is essential. Without a clear structure, stylesheets can quickly turn into a mess that’s hard to maintain.
At Starboard, I focus on writing future-proof code that grows with your project. One of the best ways to keep stylesheets organised, readable, and scalable is by using consistent naming conventions. BEM (Block Element Modifier) is, in my opinion, one of the most effective methods.
In this post I break down why structured naming matters, how BEM works, and why it’s worth investing a little extra effort up front.
The problem with generic class names
Imagine you’re working on an existing WordPress project, where another developer has been building elements. You build a block of code like this, and style the active class:
<div class="accordion">
<button class="accordion-button active">
</button>
<div class="accordion-panel">
</div>
</div>
.active {
color: red;
}
That will make the button red when the button is clicked, but what you may not know, is that there’s another block on another part of the site that’s also using .active
. Now that also has the color: red
; applied. This happens because generic class names lack specificity, leading to unintended global styling conflicts.
This is where BEM and strict naming conventions come to the rescue.
The BEM approach: Structure and clarity
BEM (Block, Element, Modifier) enforces a strict, structured approach to class naming, making styles modular and preventing conflicts. Here’s how it works:
- Block: The parent component, representing a standalone entity.
- Element: A child inside the block that has no standalone meaning.
- Modifier: A variation of a block or element that alters its appearance or behavior.
The code above would work better as a standalone component if coded like this:
<div class="accordion">
<button class="accordion__button accordion__button--active">
</button>
<div class="accordion__panel">
</div>
</div>
The styles in scss:
.accordion {
&__button {
&--active {
color: red;
}
}
}
Or CSS if you prefer:
.accordion__button--active {
color: red;
}
Example: a Testimonial block
Instead of using vague class names like .content
, .image
, or .title
, BEM ensures every class is tied to its parent block:
<div class="testimonial">
<div class="testimonial__content">
<h2 class="testimonial__title">Customer Testimonial</h2>
<p class="testimonial__text">"This service was excellent!"</p>
</div>
<div class="testimonial__image testimonial__image--rounded">
<img src="customer.jpg" alt="Happy customer" />
</div>
</div>
And the corresponding SCSS:
.testimonial {
display: flex;
justify-content: space-between;
align-items: center;
gap: 2rem;
padding: 2rem;
&__content {
width: 50%;
}
&__title {
font-size: 2rem;
font-weight: bold;
}
&__text {
font-style: italic;
}
&__image {
width: 40%;
// Modifier for rounded image
&--rounded {
img {
border-radius: 50%;
}
}
}
}
This structure ensures that styles remain self-contained and do not interfere with other components.
Naming conventions: keep it clear and consistent
To further reinforce modularity and avoid conflicts, it’s essential to follow these best practices:
1. Always name your SCSS files after the block name
If you create a new block, its SCSS file should follow the same naming pattern:
/src/sass/blocks/_testimonial.scss
That way when you end up with lots and lots of code, your file system should look like this:
/src/sass/
├── __hero.scss
├── __nav.scss
├── __testimonial.scss
This keeps files easy to find and ensures styles remain component-specific.
2. Start a new SCSS file for a new naming convention
If you need a fresh set of styles that aren’t linked to an existing block, start a new SCSS file instead of repurposing an old one. This forces you to think about naming more carefully and prevents vague class names that might unintentionally overlap with other components.
Don’t worry about creating dozens of new .scss files – that’s ok! Your SCSS will all get compiled at the end anyway.
3. Avoid global class names (e.g., .active
, .content
, .box
)
Global class names should be reserved for utility classes and never used for block-specific styles. Instead of .active
, use .button--active
or .menu__item--active
to ensure specificity.
4. Use meaningful and descriptive names
Bad example:
.card .content {
padding: 1rem;
}
Better example:
.card__content {
padding: 1rem;
}
This small change eliminates ambiguity and makes it clear which component the styles belong to.
The benefits of BEM and naming conventions
- Prevents style conflicts – No more unintended CSS overrides from vague class names.
- Easier maintenance – When you need to update a component, you know exactly where to look.
- Scalability – As your project grows, structured class names prevent chaos.
- Reusability – You can copy and paste a block’s SCSS into another project without worrying about global conflicts.
To sum up
Naming conventions like BEM might feel tedious when you’re mid-project, but they pay off massively over the lifetime of a website. Clear, consistent code reduces bugs, makes onboarding new developers easier, and keeps your site agile.
I build maintainability into every Starboard project, so if you’re planning a new project and want a site that’s designed to scale, let’s chat!