This episode covers CSS architectures: the BEM methodology with blocks, elements, and modifiers, OOCSS principles that separate structure from appearance, and utility-first using small one-off classes, including how to choose the right approach for your project.

Episode 19 covered CSS cleanliness and modularity. Episode 20 answers the follow-up question: which methodology should you use? Three dominant approaches color the CSS world — BEM, OOCSS, and utility-first — and each has strengths and weaknesses. BEM strictly organizes class names for components with clear boundaries. OOCSS separates structure from appearance so styles can be reused. Utility-first builds interfaces from small classes that reflect a single property. Why does it matter? The architecture choice affects development speed and years of maintenance ease. There's no single correct answer — you need to understand all three to choose according to your team and project context.
BEM divides class names into three parts:
/* Block: a standalone component */
.card {
border: 1px solid #e2e8f0;
border-radius: 12px;
}
/* Element: a part of a block, marked by two underscores */
.card__title {
font-size: 1.25rem;
}
.card__body {
color: #475569;
}
/* Modifier: a state variation, marked by two dashes */
.card--featured {
border-color: #2563eb;
box-shadow: 0 8px 24px rgba(37, 99, 235, 0.2);
}A block is named independently, an element is attached to a block, and a modifier expresses a variation. The main rules: an element must not stand outside its block, and a modifier must not be used without its base block. This structure makes component relationships visible directly from the class names.
<article class="card card--featured">
<h2 class="card__title">Judul Unggulan</h2>
<p class="card__body">Deskripsi kartu yang ditampilkan.</p>
</article>BEM's strengths are clarity and always-flat specificity — one block, one class. Its weakness: class names can get long and the HTML becomes dense.
OOCSS (Object-Oriented CSS) separates structure (dimensions and layout) from appearance (color and typography), then combines them through multiple classes:
/* Structure: reusable for different shapes */
.box {
padding: 16px;
border-radius: 8px;
}
/* Appearance: a skin that can attach to any shape */
.skin-peringatan {
background-color: #fef3c7;
border: 1px solid #f59e0b;
color: #92400e;
}
.skin-sukses {
background-color: #dcfce7;
border: 1px solid #16a34a;
color: #166534;
}<div class="box skin-peringatan">Peringatan penting</div>
<div class="box skin-sukses">Operasi berhasil</div>Elements with different shapes but the same skin can share classes. This separation encourages reuse and prevents duplicating identical properties. The risk: overly generic classes can make components harder to find.
Utility-first builds UIs from small classes that each represent a single property:
.p-4 { padding: 16px; }
.mb-2 { margin-bottom: 8px; }
.flex { display: flex; }
.items-center { align-items: center; }
.rounded { border-radius: 8px; }
.bg-blue { background-color: #2563eb; }
.text-white { color: white; }An interface is assembled directly in the HTML from class combinations:
<button class="flex items-center p-4 rounded bg-blue text-white">
Kirim
</button>This approach is adopted by Tailwind CSS, which provides thousands of ready-to-use utilities. Its strengths: no need to think up class names, fast changes, and consistent code. Its weakness: the HTML becomes long and the same classes repeat in many places.
The three aren't mutually exclusive — combinations are common:
/* BEM for complex reusable components */
.site-header__nav {
display: flex;
gap: 16px;
}
/* Utility for one-off spacing that doesn't need a component */
.utilities-mt-1 {
margin-top: 4px;
}A practical guide: utility-first suits fast iteration and small teams; BEM excels for components used by many teams with clear boundaries; OOCSS helps when many elements share visual patterns. Large production teams often combine BEM for components and utilities for quick adjustments.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Arsitektur CSS</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section class="section section--padat">
<h2 class="section__title">Belajar Arsitektur CSS</h2>
<button class="button button--primary">BEM</button>
<button class="button button--secondary">OOCSS</button>
<button class="button button--primary button--besar">Utility</button>
</section>
</body>
</html>* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, sans-serif; padding: 24px; }
.section { max-width: 640px; margin-inline: auto; padding: 24px; border: 1px solid #e2e8f0; border-radius: 12px; }
.section__title { margin-bottom: 16px; }
.button { display: inline-flex; align-items: center; justify-content: center; padding: 10px 18px; border-radius: 8px; font-size: 1rem; border: none; cursor: pointer; }
.button--primary { background-color: #2563eb; color: white; }
.button--secondary { background-color: #e2e8f0; color: #0f172a; }
.button--besar { padding: 14px 24px; font-size: 1.125rem; }Open the page in the browser with npx serve . and notice how one base .button class unifies the shape while modifiers change the appearance. Rewrite the utility-first version in a separate file, then compare the HTML and CSS length of both.
Mixing up __ and -- breaks readability. Establish the naming rules (block __ element -- modifier) and follow them across the whole project.
Before adding a new utility, check whether a similar one already exists. Overlapping utilities make the HTML hard to predict.
Switching methodologies leaves the stylesheet mixed up. If you intend to migrate, do it component by component and keep both during the transition.
Key takeaways: