Mastering CSS Class Naming: From Chaos to BEM and Beyond
This article explores the challenges of CSS class naming, traces its evolution from chaotic practices through atomic and modular approaches to the widely adopted BEM methodology, and provides practical rules, keyword lists, and code examples for creating clear, maintainable, and conflict‑free class structures.
Anyone who writes CSS has faced the dilemma of naming classes that are both descriptive and conflict‑free.
Should a class be generic or specific?
How can you know if a class is used elsewhere?
Typical approaches lead to messy, mixed‑language names that work only because the page renders, but they cause maintenance headaches when conflicts arise.
Why Class Naming Is Hard
Unlike IDs, classes are meant to be reusable, yet they must avoid style collisions. Reusability favors simple, abstract names, while conflict avoidance pushes for uniqueness. BEM solves this by making classes effectively unique; other strategies include scoping with parent elements, adding modifier classes, or separating styles into different files per page.
<code>// BEM
.imgslide__item__img{}
// Parent‑scoped
.imgslide .item .img{}
// Modifier class
.img{}
.img--special{}
// Different pages, different files
/* a.html & a.css */
.img{}
/* b.html & b.css */
.img{}
</code>Class naming has evolved through several stages:
Evolution Stages
Chaos: No rules, random names, often mixing Chinese and English.
Atomic: Lots of tiny utility classes combined to form a layout.
Modular: Prefixes like
.l-(layout),
.g-(global),
.m-(module) to indicate purpose.
BEM: Block‑Element‑Modifier pattern that enforces a clear hierarchy.
Chaos Stage
Early HTML projects used ad‑hoc names such as
h1.title,
div.hd-s, or
.red{color:red;font-size:14px;}, which often mixed semantics and style.
Atomic Stage
Utility classes like
.fl,
.pr,
.fs12are combined in HTML (e.g.,
div.fs12.fl.pr.tac), but this leads to long class lists and makes maintenance difficult, especially in front‑back separation scenarios.
Modular Stage
Prefixes indicate function:
.l-960,
.g-red,
.m-login. While clearer, the growing number of prefixes can become unwieldy.
BEM Stage
BEM’s long, descriptive class names (
.block__element--modifier) virtually eliminate collisions, though they can be verbose.
Learning From Others
Choose the naming style that fits the project: simple names for quick demos, atomic utilities for tiny styles, modular prefixes for larger structures, and BEM for robust, scalable codebases.
Common Class Keywords
Layout: header, footer, container, main, content, aside, page, section
Wrapper: wrap, inner
Block: region, block, box
Structure: hd, bd, ft, top, bottom, left, right, middle, col, row, grid, span
List: list, item, field
State: active, current, checked, hover, fail, success, warn, error, on, off
Navigation: nav, prev, next, breadcrumb, paging, first, last
Interaction: tips, alert, modal, pop, panel, tabs, accordion, slide, scroll, overlay
Icon: icon-
...and many others.
Simple Naming Rules
Use hyphens to separate words, e.g.,
.item-img.
Two hyphens denote a modifier, e.g.,
.item-img--small.
State classes are plain words like
.active,
.checked.
Icon classes start with
icon-, e.g.,
.icon-font.i-name.
Prefix JavaScript‑hook classes with
js-.
Limit combined classes to four.
Practical Example
Layout skeleton:
<code>header.header > .inner-center
section.section-feature > .inner-center
section.section-main > .inner-center
section.section-postscript > .inner-center
footer.footer > .inner-center
</code>When the same structure appears elsewhere, add a modifier prefix, e.g.,
.block-hd,
.modal-hd,
.article-hd. For titles, use
.page-ttor
.block-tt. To specialize a class, either extend the name (
.page-tt--user) or add a modifier class (
.page-tt.page-tt--user) or scope it with a parent (
.page-user .page-tt).
Hierarchy and Scope
Typical list markup:
<code><ul>
<li>
<a href="#"><img src="" alt=""></a>
<h3><a href="#"></a></h3>
<p></p>
</li>
</ul>
</code>Two naming approaches:
<code>// Inheritance style
ul.card-list
li.list-item
a.item-img-link > img.item-img
h3.item-tt > a.item-tt-link
p.item-text
// Keyword style
ul.card-list
li.item
a.field-img-link > img.field-img
h3.field-tt > a.field-tt-link
p.field-text
</code>Scope styles using parent classes, e.g.,
.aside-block.block--xxx > h3.block-tt .block-bd, and apply modifiers like
.block--contactto adjust specific sections.
Real‑World Example
For a sidebar contact list:
<code>ul.contact-list
li
i.item-icon.icon-font.i-xxx
a.item-tt
p.gray
</code>Base styles:
<code>.gray {}
.contact-list {
li {}
.item-icon {}
.item-tt {}
}
</code>To customize only this sidebar, wrap it with a modifier class:
<code>.block--contact {
.contact-list {
li {}
}
}
</code>In summary, effective CSS class naming starts with a solid keyword set, then applies modifier conventions, hierarchical structures, and scoped rules to achieve readability, maintainability, and conflict avoidance.
Original article first published on IMWeb . Please credit the source when reposting.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.