CSS Mimarisi (BEM/SCSS/Utility)
İlan 1 özel · İlan 1

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.
💡
Bu sitede canlı örneği varBu projenin kendi 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şımScope nasıl sağlanırArtıEksi
BEMİnsan disiplini (konvansiyon)Araç gerektirmez, her yerde çalışırDisiplin bozulursa çakışma riski, uzun class isimleri
CSS ModulesBuild-time otomatik hash'lemeÇakışma imkansız, Next.js'te native destekDinamik class birleştirme için clsx gibi yardımcı gerekir
Utility-firstAtomik 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
// 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" },
};
⚠️
Mülakat sorusu ihtimali yüksek"Ant Design kullanırken tasarımcı farklı bir şey istedi, ne yaparsın?" — iyi cevap: Ant Design'ın ConfigProvider/theme token sistemiyle özelleştirme, gerekirse component'i "wrap" edip kendi API'nı koyma; component'i sıfırdan yazmak son çare.

Egzersizler

1) Aynı projede hem BEM hem CSS Modules kullanmak mantıklı mı? Ne zaman?
Evet, olabilir. Örnek: global, sayfa genelinde tekrar eden temel elementler (typography, buton, layout grid) BEM ile global bir stylesheet'te; özel, tek component'e ait stiller CSS Modules ile scoped tutulur. Önemli olan ekipçe tutarlı bir kural belirlemek — karışıklığın kendisi değil, kuralsızlık sorun yaratır.
2) Utility-first yaklaşımın en büyük eleştirisi 'HTML'i kirletiyor' şeklinde. Buna nasıl cevap verirsin?
Kısmen doğru ama trade-off bilinçli: stil ile markup'ı ayırmak component bazında değil dosya bazında yapılır — component küçük ve tek sorumluluklu tutulduğunda class listesi de yönetilebilir kalır. Ayrıca "iki dosya arasında gidip gelmeden stilin ne olduğunu görmek" birçok ekip için üretkenlik kazancı sayılıyor.