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:
| Part | What it is | Written as | Example |
|---|---|---|---|
| Block | A standalone component that makes sense on its own | block | event-card |
| Element | A part of a block that has no meaning outside it | block__element (two underscores) | event-card__title |
| Modifier | A different version or state of a block or element | block--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">🎫</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 theh3its own class instead. - No element selectors inside components (
.event-card h3). If the HTML changes fromh3toh2, 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:
- Settings: custom properties for colours, spacing and fonts on
:root. - Base: plain element styles like
body,aandimg. No classes here. - Layout: page regions and wrappers such as
.container,.site-headerand grids. - Components: your BEM blocks, one block per group, such as
.event-cardand.btn. - 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, notEventCard. - 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:
- Add an
event-card--sold-outmodifier that makes the card grey and hides the button. - Add a
btn--outlinemodifier and use it on one of the Details buttons. - 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 palso styles every paragraph you add later. Give each part its own element class. - Names that describe the look.
.box--purplebecomes 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-cardblock with elements for the photo, the name and the role. - Turn
.leadinto amember-card--leadmodifier. - 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__elementandblock--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.