Skip to content

Article

BEM and SMACSS in 2026: still worth it?

Why an old naming convention keeps large, framework-free front ends calm, readable and easy to hand over.

BEM is well into its teens and SMACSS isn’t far behind. In front-end years, that’s ancient. Utility-first CSS won the popularity contest, CSS Modules and scoped styles solved naming for component frameworks, and native CSS gained nesting, cascade layers and container queries.

And yet this site — and most of the agency projects I build — still uses SMACSS categories with BEM naming. Not out of nostalgia. Because for a certain kind of project, it is still the calmest way to write CSS that other people can pick up.

What the convention looks like

SMACSS gives every class a category, which I mark with a prefix:

  • l- layout: page-level structure — l-container, l-footer.
  • s- sections: one block of a page — s-contact, s-post.
  • c- components: reusable pieces — c-button, c-chat, c-postList.
  • u- utilities: single-purpose helpers — u-srOnly, u-reveal.
  • is- states: toggled by JavaScript or the server — is-active, is-copied.

BEM then names what’s inside a component: block, __element, --modifier. Components are camelCase, so the separators stay readable:

<li class="c-postList__item">
  <a class="c-postList__link" href="/blog/…">
    <p class="c-postList__meta">…</p>
    <h2 class="c-postList__title">…</h2>
  </a>
</li>

You can read that markup cold and know exactly which file styles it, what else might affect it, and what you can safely change.

Why it still earns its place

It survives handoffs. Most of my work ends up in someone else’s hands — an agency team, a client’s in-house developer, a WordPress site edited in Elementor for years. A naming convention is documentation that travels with the markup. Nobody needs to learn a framework to understand c-chat__bubble.

It keeps specificity flat. Every selector is a single class. No nesting battles, no !important arms race, no wondering why a rule doesn’t apply.

It makes deletion safe. When c-logoWall goes, its styles go with it: one file, one prefix, nothing leaking elsewhere. Dead CSS is easy to find because its name tells you where it lived.

It works without a build step or framework. Plain HTML, PHP templates, WordPress, a Vite bundle — the convention doesn’t care what renders the markup.

What modern CSS changed

The convention didn’t stay frozen. Modern CSS made it better:

  • Native nesting lets a component file read as one block: &__title, &:hover, .is-chat & — the SCSS I write today is close to what the browser understands natively.
  • :where() keeps base styles at zero specificity, so components always win without a fight.
  • Cascade layers (@layer) can mirror the SMACSS order — base, layout, components, utilities — and make that order explicit instead of relying on file order.
  • Container queries let a component respond to the space it’s given, which fits the “component owns its styles” idea perfectly.
  • Custom properties turn modifiers into variables: style="--columns: 3" instead of a new modifier for every variant.

Where it falls short

It isn’t free, and I don’t pretend otherwise:

  • Names are long. c-serviceWheel__approach is a mouthful. I accept it; the clarity is worth the characters.
  • It needs discipline. A convention nobody enforces becomes a suggestion. A short README and a stylelint pattern rule do most of the enforcing.
  • Utility-first is faster for prototypes. For a throwaway prototype, I’d reach for utilities too. For a site that someone will maintain for five years, I wouldn’t.
  • Component frameworks already scope styles. In a React or Vue app with CSS Modules, BEM’s isolation is redundant. The category prefixes still help, though.

A naming convention is a letter to the next developer. BEM and SMACSS are just very clear handwriting.

So, still worth it?

For framework-free sites, CMS builds and anything that changes hands: yes. It keeps CSS predictable, makes ownership obvious and costs nothing at runtime. For component-framework apps, take the parts that help — the categories, the states — and let the framework handle the scoping.

The best argument for it, though, is the least technical: two years from now, someone will open this code without me. I want them to understand it on the first read.

Topics

Published

Reactions0

Share

Comments 0

  1. Nothing here yet — start the conversation.

Who’s it from?

Pick a face

Comments are read before they appear; your email is only there if I need to reply privately.

Keep reading