CSS mimarisi: BEM, SCSS, CSS Modules, Utility-first
Hepsi aynı problemi çözmeye çalışır: büyük bir kod tabanında stil çakışmalarını (CSS specificity savaşları) önlemek. Fark, bunu nerede ve nasıl yaptıkları.
1. BEM — Block, Element, Modifier
Saf konvansiyon, hiçbir araç gerektirmez. Disiplinle iş görür: her class ismi blok__eleman--degisken kalıbına uyar, böylece iç içe seçicilere hiç ihtiyaç kalmaz.
<!-- İYİ: Block__Element--Modifier -->
<div class="card card--highlighted">
<h3 class="card__title">Kampanya</h3>
<p class="card__body">Detay metni…</p>
<button class="card__cta card__cta--disabled">Katıl</button>
</div>
/* KÖTÜ: iç içe seçiciler, özgüllük (specificity) savaşı çıkarır */
.card div h3 { font-weight: 700; } /* neyi seçtiği belirsiz, kırılgan */
.cardTitleHighlighted { color: red; } /* hangi bileşene ait belirsiz */2. SCSS/SASS — CSS'e programlama gücü katmak
Değişkenler, iç içe yazım (nesting), mixin'ler ve dosyaları parçalara bölme (@import/@use) kazandırır. Derleme zamanında düz CSS'e indirgenir — tarayıcı SCSS bilmez.
// _variables.scss
$primary: #3454d1;
$radius: 10px;
@mixin flex-center { display: flex; align-items: center; justify-content: center; }
// Card.scss
.card {
padding: 16px;
border-radius: $radius;
@include flex-center;
&__title { // .card__title'a derlenir
font-weight: 700;
color: $primary;
}
&--dark { // .card--dark'a derlenir
background: #111;
}
}3. CSS Modules — otomatik izolasyon
Next.js'te sıfır konfigürasyonla gelir. Her .module.css dosyasındaki class isimleri build aracı tarafından benzersizleştirilir — BEM'deki disiplini araç seviyesinde zorunlu kılar.
/* Card.module.css */
.card { padding: 16px; border-radius: 10px; }
.title { font-weight: 700; }
// Card.tsx
import styles from "./Card.module.css";
export function Card() {
return (
<div className={styles.card}>
<h3 className={styles.title}>Kampanya</h3>
</div>
);
}
// Build sırasında .card → .Card_card__a1b2c gibi hash'lenir.
// Başka bir dosyadaki .card ASLA bununla çakışmaz.Sidebar.tsx'i tam olarak bunu kullanıyor — src/components/Sidebar.module.css dosyasına bak: styles.treeItem gibi importlanıp kullanılıyor. Mülakatta "CSS Modules kullandın mı" sorusuna somut bir örnekle cevap verebilirsin.4. Utility-first (Tailwind tarzı)
Ayrı bir CSS dosyası yazmak yerine, önceden tanımlı atomik class'ları JSX içinde birleştirirsin. Hız kazandırır, tutarlı bir spacing/renk skalasına zorlar.
<div className="p-4 rounded-lg bg-white shadow-md">
<h3 className="font-bold text-lg text-slate-900">Kampanya</h3>
<button className="mt-3 px-4 py-2 rounded-md bg-blue-600 text-white
hover:bg-blue-700 disabled:opacity-50">
Katıl
</button>
</div>
/* Ayrı bir .css dosyası yok — stil JSX'in içinde "yaşıyor". */| Yaklaşım | Scope nasıl sağlanır | Artı | Eksi |
|---|---|---|---|
| BEM | İnsan disiplini (konvansiyon) | Araç gerektirmez, her yerde çalışır | Disiplin bozulursa çakışma riski, uzun class isimleri |
| CSS Modules | Build-time otomatik hash'leme | Çakışma imkansız, Next.js'te native destek | Dinamik class birleştirme için clsx gibi yardımcı gerekir |
| Utility-first | Atomik class'lar zaten global ama tek amaçlı | Çok hızlı prototipleme, tutarlı tasarım skalası | JSX kalabalıklaşır, ekipçe alışkanlık gerektirir |
Design System, Storybook, Ant Design
Design system, buton/renk/spacing kurallarının kod haline gelmiş, tek kaynaktan yönetilen hali. Ant Design hazır bir React component kütüphanesi — kurumsal projelerde hız kazandırır ama özelleştirme (customization) sınırları vardır. Storybook ise component'leri sayfa/route'tan bağımsız, izole bir ortamda geliştirip kataloglamanı sağlar — "component-driven development".
// Buton.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Buton } from "./Buton";
const meta: Meta<typeof Buton> = { title: "UI/Buton", component: Buton };
export default meta;
export const Primary: StoryObj<typeof Buton> = {
args: { etiket: "Kaydet", varyant: "primary" },
};
export const Ghost: StoryObj<typeof Buton> = {
args: { etiket: "İptal", varyant: "ghost" },
};ConfigProvider/theme token sistemiyle özelleştirme, gerekirse component'i "wrap" edip kendi API'nı koyma; component'i sıfırdan yazmak son çare.