Learn
🤖 AI Hub 📰 News 📖 Dictionary 🧰 Resources
Grow
💼 Jobs 🚀 Community 🏆 Challenges
Explore by Stage
🌑 Zero 📚 Learn 🔧 Practice 🏗 Build 🚀 Launch 💰 Earn
Account
Login Sign Up
🏗️HTML 🎨CSS ⚡JavaScript 🐙Git & GitHub ⚛️React Soon 📘TypeScript Soon 🐍Python 🗄️Database & SQL Soon 🌐Web Development Soon ☁️Cloud & DevOps Soon 🤖AI & ML Soon 📄Resume Prep Soon 🎤Interview Prep Soon 💼Freelancing Soon 🚀SaaS & Side Projects Soon 🤖Automation Soon
Advanced 🕑 16 min read 👁 3 views 📅 Oct 21, 2026

Organising CSS: BEM Naming and a Clean Structure

Stop CSS fights in team projects. Learn BEM naming (block, element, modifier), keep specificity flat and organise your stylesheet into settings, base, layout, components and utilities.

Three Friends, One Stylesheet, Many Fights

Rohan, Divya and Sameer are building the website for Utsav 2026, their college fest. They split the work: Rohan does the home banner, Divya does the sponsors page and Sameer does the events list. They all write into the same style.css file.

Two weeks later, the group chat is full of angry messages. "Who made my heading small?" "Why is the sponsor list pink?" "I had to add !important four times to make my button orange!" Nobody broke anything on purpose. The CSS simply had no rules for how to name things or where to put them.

This lesson teaches the fix that many professional teams use: the BEM naming method plus a clear order for your stylesheet. It is not new CSS syntax. It is a set of habits that keeps CSS calm as a project and a team grow.

Why CSS Gets Messy

Two features of CSS cause most of the trouble in group projects.

Problem 1: Every name is global

A class like .title applies to every element with that class on every page. When two people use the same short, general name for different things, the rule written later wins, and one of them silently breaks.

<!DOCTYPE html>
<html lang="en">
<head>
<style>
  /* Rohan wrote this for the hero banner */
  .title { font-size: 2.5rem; color: #c2185b; text-align: center; }

  /* Divya wrote this much later, for the sponsors list */
  .title { font-size: 1rem; color: #333; text-align: left; }
</style>
</head>
<body>
  <section>
    <h1 class="title">Utsav 2026</h1>
    <p>Three days of music, dance and code.</p>
  </section>
  <section>
    <h3 class="title">Our Sponsors</h3>
  </section>
</body>
</html>

Both headings now look like the sponsor title, because Divya's rule came last. Rohan did nothing wrong, and he has no idea why his banner changed.

Problem 2: Specificity wars

As you saw in the CSS Specificity and Cascade lesson, a selector with an ID or many classes beats a simpler one, no matter where it appears. When the first rule is long, every change after it has to be even longer. In the end, someone reaches for !important, and then the next person needs !important too.

<!DOCTYPE html>
<html lang="en">
<head>
<style>
  #events .list .card h3 { color: #1565c0; }

  /* Sameer wants the featured event's title in orange. This loses: */
  .featured-title { color: #e65100; }

  /* So he writes a longer selector... */
  #events .list .card.featured h3 { color: #e65100; }

  /* ...and next week someone else adds !important. The war has begun. */
</style>
</head>
<body>
  <section id="events">
    <div class="list">
      <div class="card"><h3>Battle of Bands</h3></div>
      <div class="card featured"><h3 class="featured-title">Hackathon</h3></div>
    </div>
  </section>
</body>
</html>

The root cause is a selector that is far stronger than it needs to be. The cure is to keep every selector simple and equally strong.

BEM: Block, Element, Modifier

BEM is a naming method. Every class name tells you three things:

PartWhat it isWritten asExample
BlockA standalone component that makes sense on its ownblockevent-card
ElementA part of a block that has no meaning outside itblock__element (two underscores)event-card__title
ModifierA different version or state of a block or elementblock--modifier (two hyphens)event-card--featured

Here is an event card written with BEM. Look at the class names: you can understand the structure without reading the HTML.

<!DOCTYPE html>
<html lang="en">
<head>
<style>
  /* Block */
  .event-card {
    background: #ffffff;
    border: 1px solid #e0d7f0;
    border-radius: 12px;
    padding: 16px;
    max-width: 280px;
    font-family: system-ui, sans-serif;
  }
  /* Elements: parts of the block */
  .event-card__title { margin: 0 0 4px; font-size: 1.2rem; color: #4a148c; }
  .event-card__time  { margin: 0; color: #666; font-size: 0.9rem; }
  .event-card__tag   { display: inline-block; margin-top: 8px; padding: 2px 8px;
                       border-radius: 999px; background: #f3e5f5; font-size: 0.8rem; }

  /* Modifier: a different version of the block */
  .event-card--featured { border: 2px solid #ff6f00; background: #fff8e1; }
</style>
</head>
<body>
  <article class="event-card">
    <h3 class="event-card__title">Battle of Bands</h3>
    <p class="event-card__time">Day 1, 6:00 PM, Open Air Theatre</p>
    <span class="event-card__tag">Music</span>
  </article>
  <br>
  <article class="event-card event-card--featured">
    <h3 class="event-card__title">24 Hour Hackathon</h3>
    <p class="event-card__time">Day 2, 9:00 AM, Computer Lab 3</p>
    <span class="event-card__tag">Tech</span>
  </article>
</body>
</html>

Notice three things. First, a modifier is always added next to the base class: class="event-card event-card--featured". The base class gives the normal look and the modifier changes only what is different. Second, every selector is a single class, so they all have the same specificity. The order in the file decides, and there are no wars. Third, the names are long, and that is fine. event-card__title will never clash with Divya's sponsor heading.

A button with BEM

Buttons are the classic example of modifiers. One block, several versions, and you can combine modifiers freely:

<!DOCTYPE html>
<html lang="en">
<head>
<style>
  .btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 10px 18px;
    border: 2px solid transparent;
    border-radius: 8px;
    font: inherit;
    font-weight: bold;
    cursor: pointer;
    background: #ede7f6;
    color: #311b92;
  }
  .btn__icon { font-size: 1.1em; }

  .btn--primary { background: #6a1b9a; color: #ffffff; }
  .btn--outline { background: transparent; border-color: #6a1b9a; color: #6a1b9a; }
  .btn--small   { min-height: 32px; padding: 4px 10px; font-size: 0.85rem; }
</style>
</head>
<body style="font-family: system-ui, sans-serif;">
  <button class="btn">Default</button>
  <button class="btn btn--primary"><span class="btn__icon">&#127915;</span> Register now</button>
  <button class="btn btn--outline">View schedule</button>
  <button class="btn btn--primary btn--small">Small primary</button>
</body>
</html>

Want a new kind of button? Add one modifier class. You never need to touch the base .btn rule or the HTML of buttons that already exist.

Keep Specificity Flat

BEM works because of one simple rule: style with one class per selector. In practice, that means:

  • No IDs in your CSS. Keep IDs for links (href="#events") and JavaScript.
  • No long chains like .events .list .card h3. Give the h3 its own class instead.
  • No element selectors inside components (.event-card h3). If the HTML changes from h3 to h2, the style still works with a class.
  • A modifier that changes an element may use two classes, such as .event-card--featured .event-card__tag. That is the one accepted exception.
!important is a sign that the cascade is out of control. In a BEM project you should almost never need it. The one common exception is a utility class whose whole job is to always win.

A Clean File Structure

Good names solve clashes. A clear order solves the "where do I put this?" problem. Write your stylesheet in sections, from the most general to the most specific:

  1. Settings: custom properties for colours, spacing and fonts on :root.
  2. Base: plain element styles like body, a and img. No classes here.
  3. Layout: page regions and wrappers such as .container, .site-header and grids.
  4. Components: your BEM blocks, one block per group, such as .event-card and .btn.
  5. Utilities: tiny single-purpose classes such as .u-text-center. They come last so they can override a component when needed.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
  /* ============ 1. Settings: tokens ============ */
  :root {
    --color-brand: #6a1b9a;
    --color-text: #222222;
    --space: 16px;
  }

  /* ============ 2. Base: plain elements only ============ */
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; color: var(--color-text); }
  img { max-width: 100%; display: block; }

  /* ============ 3. Layout: page regions ============ */
  .container { width: min(100% - 2 * var(--space), 960px); margin-inline: auto; }
  .site-header { background: var(--color-brand); color: #fff; padding-block: var(--space); }

  /* ============ 4. Components: BEM blocks ============ */
  .badge { display: inline-block; padding: 2px 8px; border-radius: 999px;
           background: #fff; color: var(--color-brand); font-size: 0.8rem; }
  .badge--live { background: #d50000; color: #fff; }

  /* ============ 5. Utilities: one job each ============ */
  .u-text-center { text-align: center; }
  .u-mt-0 { margin-top: 0; }
</style>
</head>
<body>
  <header class="site-header">
    <div class="container u-text-center">
      <h2 class="u-mt-0">Utsav 2026</h2>
      <span class="badge badge--live">Live now</span>
    </div>
  </header>
</body>
</html>

On a bigger project, each section, or even each component, can become its own file (base.css, layout.css, components/event-card.css), joined in the same order. The order matters because of the cascade: later rules win when specificity is equal.

Utilities, Comments and Naming Tips

Utility classes do one small job. A prefix such as u- makes them easy to spot. Keep only a handful, for things you really repeat, such as text alignment, a margin reset or a visually hidden label.

Comments should explain why, not what. /* red background */ adds nothing. /* matches the sponsor's logo colour, do not change */ saves your teammate an hour.

Naming tips:

  • Name by purpose, not by look: .btn--danger, not .btn--red. The colour may change, the purpose will not.
  • Use small letters and single hyphens inside a word group: event-card, not EventCard.
  • Agree on the rules with your team before you write code, and write them in the project's README.

You may also hear about tools such as Tailwind CSS, which build pages almost entirely from utility classes, or CSS Modules, which make class names unique automatically. They solve the same problems in other ways. You do not need them now, and the habits from this lesson will help you with any of them.

Real-Life Example: The Utsav 2026 Events Section

Here is Sameer's events section, rewritten after the friends agreed on BEM and the five sections. Each block (section-head, event-card, btn) is independent. An element can also be a block at the same time: the link is both a btn and the event-card__action, so the button looks like every other button, while the card decides where it sits.

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
  /* ===== Settings ===== */
  :root {
    --color-brand: #6a1b9a;
    --color-accent: #ff6f00;
    --color-surface: #ffffff;
    --color-bg: #f7f3fb;
    --color-text: #222222;
    --color-muted: #666666;
    --radius: 12px;
  }

  /* ===== Base ===== */
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: var(--color-bg); color: var(--color-text); }
  h2, h3 { line-height: 1.2; }

  /* ===== Layout ===== */
  .container { width: min(100% - 32px, 1000px); margin-inline: auto; }
  .section { padding-block: 32px; }

  /* ===== Components ===== */
  /* Section heading */
  .section-head { margin-bottom: 16px; }
  .section-head__title { margin: 0; font-size: 1.8rem; color: var(--color-brand); }
  .section-head__subtitle { margin: 4px 0 0; color: var(--color-muted); }

  /* Event grid */
  .event-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
    gap: 16px;
  }

  /* Event card */
  .event-card {
    display: flex;
    flex-direction: column;
    background: var(--color-surface);
    border: 1px solid #e0d7f0;
    border-radius: var(--radius);
    padding: 16px;
  }
  .event-card__tag { align-self: flex-start; padding: 2px 10px; border-radius: 999px;
                     background: #f3e5f5; color: var(--color-brand); font-size: 0.8rem; }
  .event-card__title { margin: 10px 0 4px; font-size: 1.2rem; }
  .event-card__meta { margin: 0 0 16px; color: var(--color-muted); font-size: 0.9rem; }
  .event-card__action { margin-top: auto; }
  .event-card--featured { border: 2px solid var(--color-accent); }
  .event-card--featured .event-card__tag { background: var(--color-accent); color: #fff; }

  /* Button */
  .btn { display: inline-block; min-height: 44px; padding: 10px 16px; border-radius: 8px;
         font-weight: bold; text-decoration: none; text-align: center;
         background: #ede7f6; color: var(--color-brand); }
  .btn--primary { background: var(--color-brand); color: #fff; }
  .btn--block { display: block; }

  /* ===== Utilities ===== */
  .u-text-center { text-align: center; }
</style>
</head>
<body>
  <section class="section">
    <div class="container">
      <div class="section-head u-text-center">
        <h2 class="section-head__title">Events at Utsav 2026</h2>
        <p class="section-head__subtitle">Three days, twelve events, one campus</p>
      </div>

      <div class="event-grid">
        <article class="event-card">
          <span class="event-card__tag">Music</span>
          <h3 class="event-card__title">Battle of Bands</h3>
          <p class="event-card__meta">Day 1, 6:00 PM, Open Air Theatre</p>
          <a class="btn btn--block event-card__action" href="#">Details</a>
        </article>
        <article class="event-card event-card--featured">
          <span class="event-card__tag">Featured</span>
          <h3 class="event-card__title">24 Hour Hackathon</h3>
          <p class="event-card__meta">Day 2, 9:00 AM, Computer Lab 3. Teams of up to four.</p>
          <a class="btn btn--primary btn--block event-card__action" href="#">Register</a>
        </article>
        <article class="event-card">
          <span class="event-card__tag">Dance</span>
          <h3 class="event-card__title">Folk Dance Night</h3>
          <p class="event-card__meta">Day 3, 7:00 PM, Main Ground</p>
          <a class="btn btn--block event-card__action" href="#">Details</a>
        </article>
      </div>
    </div>
  </section>
</body>
</html>

Try these changes:

  1. Add an event-card--sold-out modifier that makes the card grey and hides the button.
  2. Add a btn--outline modifier and use it on one of the Details buttons.
  3. Copy one card and paste it inside a different section of the page. It still looks right, because it does not depend on where it lives.

Common Mistakes

  • Grandchild chains like .menu__item__link. BEM names should not copy the HTML tree. Every element belongs directly to the block: .menu__link.
  • A modifier without the base class. class="menu__link--active" alone loses all the base styles. Always write both classes.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
  .menu { display: flex; gap: 8px; list-style: none; padding: 0; }
  /* Grandchild chain, tied to the HTML structure */
  .menu__item__link { padding: 8px; background: #ede7f6; text-decoration: none; }
  /* Modifier used without the base class */
  .menu__item__link--active { background: #6a1b9a; color: #fff; }
</style>
</head>
<body>
  <ul class="menu">
    <li><a class="menu__item__link" href="#">Home</a></li>
    <li><a class="menu__item__link--active" href="#">Events</a></li>
  </ul>
</body>
</html>

The fixed version uses flat element names and keeps the base class next to the modifier:

<!DOCTYPE html>
<html lang="en">
<head>
<style>
  .menu { display: flex; gap: 8px; list-style: none; padding: 0; }
  .menu__link { display: inline-block; padding: 8px; background: #ede7f6; text-decoration: none; }
  .menu__link--active { background: #6a1b9a; color: #fff; }
</style>
</head>
<body>
  <ul class="menu">
    <li class="menu__item"><a class="menu__link" href="#">Home</a></li>
    <li class="menu__item"><a class="menu__link menu__link--active" href="#">Events</a></li>
  </ul>
</body>
</html>
  • Going back to tag selectors inside blocks. .event-card p also styles every paragraph you add later. Give each part its own element class.
  • Names that describe the look. .box--purple becomes a lie when the brand colour changes. Name the role: .box--highlight.

Practice Task: Clean Up the Team Section

The "Meet the Team" section of the fest site uses an ID and tag selectors. Rewrite it.

  • Create a member-card block with elements for the photo, the name and the role.
  • Turn .lead into a member-card--lead modifier.
  • Remove the ID from the CSS completely. Every selector should be a single class (or a plain element in the Base section).
  • Organise the CSS into the five sections, with colours as tokens.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
  /* Messy CSS: rewrite it with BEM names and the five sections */
  body { font-family: system-ui, sans-serif; }
  #team .box { border: 1px solid #ddd; border-radius: 10px; padding: 12px; max-width: 240px; }
  #team .box img { width: 100%; border-radius: 50%; }
  #team .box h3 { margin: 8px 0 0; }
  #team .box p { color: #777; margin: 4px 0 0; }
  #team .box.lead { border-color: #6a1b9a; background: #f7f3fb; }
</style>
</head>
<body>
  <section id="team">
    <div class="box">
      <img src="https://picsum.photos/200/200?1" alt="Photo of Rohan">
      <h3>Rohan</h3>
      <p>Design</p>
    </div>
    <div class="box lead">
      <img src="https://picsum.photos/200/200?2" alt="Photo of Divya">
      <h3>Divya</h3>
      <p>Team lead and front end</p>
    </div>
  </section>
</body>
</html>
Show one possible answer (try it yourself first!)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
  /* ===== Settings ===== */
  :root { --color-brand: #6a1b9a; --color-border: #dddddd; --color-muted: #777777; }

  /* ===== Base ===== */
  body { font-family: system-ui, sans-serif; }
  img { max-width: 100%; display: block; }

  /* ===== Layout ===== */
  .team-grid { display: flex; flex-wrap: wrap; gap: 16px; }

  /* ===== Components ===== */
  .member-card { border: 1px solid var(--color-border); border-radius: 10px; padding: 12px; max-width: 240px; }
  .member-card__photo { width: 100%; border-radius: 50%; }
  .member-card__name { margin: 8px 0 0; }
  .member-card__role { margin: 4px 0 0; color: var(--color-muted); }
  .member-card--lead { border-color: var(--color-brand); background: #f7f3fb; }

  /* ===== Utilities ===== */
  .u-text-center { text-align: center; }
</style>
</head>
<body>
  <section class="team-grid">
    <div class="member-card u-text-center">
      <img class="member-card__photo" src="https://picsum.photos/200/200?1" alt="Photo of Rohan">
      <h3 class="member-card__name">Rohan</h3>
      <p class="member-card__role">Design</p>
    </div>
    <div class="member-card member-card--lead u-text-center">
      <img class="member-card__photo" src="https://picsum.photos/200/200?2" alt="Photo of Divya">
      <h3 class="member-card__name">Divya</h3>
      <p class="member-card__role">Team lead and front end</p>
    </div>
  </section>
</body>
</html>

Key Takeaways

  • CSS gets messy because class names are global and strong selectors start specificity wars.
  • BEM names are block, block__element and block--modifier. A modifier always sits next to its base class.
  • Style with one class per selector: no IDs, no long chains and no tag selectors inside components.
  • Order the stylesheet as settings, base, layout, components, utilities.
  • Name classes by purpose, comment the "why" and agree on the rules with your team first.

❓ Frequently Asked Questions

No. BEM is one popular convention among several. What matters is that your team agrees on one clear naming system and follows it everywhere, and BEM is a simple, well-known choice for that.
Single hyphens are already used inside names such as event-card. The double characters make the boundaries between block, element and modifier easy to see and easy to search for.
Not in the name. Write menu__link, not menu__item__link, even if the link sits inside the item. If a part grows big enough to have its own parts, turn it into a new block.
Learn plain CSS and good organisation first. Tailwind and similar tools are easier to understand once you know the problems they solve, and many projects still use plain CSS with BEM.
Was this lesson helpful?

🎯 Finished this lesson?

🔗 Related Tutorials
🤖 Got a Doubt? Ask AI
Get instant answers in Hindi or English
🤖
Z2T Bot
Online
Ask me anything about this tutorial — I'm here! 👋