Clean Markup

Clean CSS Architecture with BEM Naming Conventions

Clean CSS Architecture with BEM Naming Conventions

As stylesheets grow across large frontend projects, deeply nested selectors like .sidebar ul li a.active and !important overrides quickly turn CSS into an fragile tangle. Adopting BEM (Block, Element, Modifier) keeps every selector at a single class specificity while making the relationship between your HTML markup and CSS rules immediately clear.

Example

<!-- Avoid: Tightly coupled tag hierarchy -->
<div class="post featured">
  <div class="image"><img src="cover.webp" alt="" /></div>
  <h2><a href="/post">Article Title</a></h2>
</div>

<!-- Prefer: Flat, self-documenting BEM classes -->
<article class="post-card post-card--featured">
  <div class="post-card__media">
    <img class="post-card__image" src="cover.webp" alt="Article Title" />
  </div>
  <h2 class="post-card__title">
    <a class="post-card__link" href="/post">Article Title</a>
  </h2>
</article>

Input : Component HTML and stylesheet
Output : Flat-specificity CSS architecture free of cascade collisions.

Implementation

/* Block */
.post-card {
  border: 1px solid #dedede;
  padding: 20px 30px;
  background-color: #ffffff;
  transition: border-color 200ms ease;
}

/* Modifier */
.post-card--featured {
  border-color: #60e1cc;
  box-shadow: 0 6px 18px rgba(8, 40, 64, 0.06);
}

/* Elements */
.post-card__media {
  overflow: hidden;
  margin-bottom: 16px;
}

.post-card__image {
  display: block;
  width: 100%;
  height: auto;
}

.post-card__title {
  margin: 0 0 10px 0;
  font-size: 24px;
}

.post-card__link {
  color: #082840;
  text-decoration: none;
}

.post-card__link:hover {
  color: #04ae92;
}

Main Point: Never mirror the full DOM tree in your CSS selectors (block__row__col__title); every child inside a block is simply block__element regardless of how many HTML wrapper tags sit in between.

Credits

Photo by Igor Miske

← Home