aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Frontend & UI

CSS Dark Mode: prefers-color-scheme ve Toggle Rehberi

İyi bir CSS dark mode kurulumu üç parçadan oluşur: renkleri tek yerden yöneten CSS değişkenleri, kullanıcının sistem tercihini okuyan prefers-color-scheme medya sorgusu ve isteyen kişinin temayı elle değiştirebileceği küçük bir toggle. Bu üçünü doğru bağladığında karanlık tema; tutarlı, kalıcı ve sayfa açılışında titremeyen (flicker) bir deneyime dönüşür. Bu rehberde sıfırdan, gerçek ve çalışan kodla nasıl kurulduğunu adım adım anlatıyorum.

Renkleri CSS değişkenlerine taşı

Karanlık temanın temel mantığı şudur: HTML'de hiçbir şeyi değiştirmeden sadece renk değerlerini değiştirebilmek. Bunu sağlamanın en temiz yolu, tüm renkleri :root üzerinde tanımlanmış CSS özel özellikleriyle (custom properties) yönetmektir. Böylece bileşenlerin kendisi soyut isimler kullanır, gerçek renk değeri tek bir yerde durur.

:root {
  --bg: #ffffff;
  --text: #1a1a1a;
  --muted: #5a5a5a;
  --surface: #f4f4f5;
  --accent: #2563eb;
}

body {
  background: var(--bg);
  color: var(--text);
}

.card {
  background: var(--surface);
  border: 1px solid #e4e4e7;
}

Artık tema değiştirmek, bu beş değişkenin değerini güncellemek kadar basit. .card veya body gibi yüzlerce kuralı tek tek elle değiştirmek zorunda kalmazsın.

prefers-color-scheme ile sistem tercihini oku

Kullanıcıların çoğu işletim sistemi düzeyinde bir tema seçmiştir. prefers-color-scheme medya sorgusu tam olarak bu tercihi yakalar. Sayfan, kullanıcı hiçbir şeye tıklamadan onun cihaz ayarına uygun açılır:

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f0f10;
    --text: #ededed;
    --muted: #a1a1aa;
    --surface: #1a1a1d;
    --accent: #60a5fa;
  }
}

Dikkat edilmesi gereken birkaç nokta var. Karanlık temada saf siyah (#000) yerine çok koyu bir gri (#0f0f10 gibi) kullan; saf siyah üzerinde beyaz metin gözü yorar ve "halation" denen bulanıklık yapar. Aynı şekilde metni de saf beyaz değil, hafif kırık beyaz tut. Vurgu renklerini de karanlık zeminde biraz açman gerekir; aydınlık temada güzel duran koyu mavi, karanlıkta sönük kalır.

Manuel bir toggle ekle

Sistem tercihi iyi bir başlangıç ama kullanıcı her zaman temayı kendi seçmek ister. Bunun için tercihi html etiketine bir data-theme niteliği olarak yazar ve CSS'i buna göre kurarız. Önce CSS'i üç duruma göre düzenle: varsayılan (aydınlık), sistemden gelen karanlık ve elle seçilmiş karanlık.

/* Kullanıcı elle koyu seçtiyse */
:root[data-theme="dark"] {
  --bg: #0f0f10;
  --text: #ededed;
  --muted: #a1a1aa;
  --surface: #1a1a1d;
  --accent: #60a5fa;
}

/* Kullanıcı elle açık seçtiyse, sistem koyu olsa bile */
:root[data-theme="light"] {
  --bg: #ffffff;
  --text: #1a1a1a;
}

Buradaki incelik şu: data-theme hiç yoksa prefers-color-scheme devrede kalır; kullanıcı bir kez seçim yaptıysa onun seçimi sistemi ezer. JavaScript tarafı da bu niteliği değiştirip seçimi hatırlamaktan ibaret:

const btn = document.querySelector("#theme-toggle");

btn.addEventListener("click", () => {
  const root = document.documentElement;
  const current = root.getAttribute("data-theme");
  // Mevcut görünen temayı hesapla
  const isDark = current
    ? current === "dark"
    : matchMedia("(prefers-color-scheme: dark)").matches;
  const next = isDark ? "light" : "dark";
  root.setAttribute("data-theme", next);
  localStorage.setItem("theme", next);
});

Flicker'ı (FOUC) önle

En sık yapılan hata budur: tema tercihini sayfa tamamen yüklendikten sonra uygulamak. Bu durumda karanlık tema seven kullanıcı, milisaniyelerce beyaz bir ekran görür; buna FOUC (Flash of Unstyled Content) ya da tema flicker'ı denir. Çözüm, localStorage'daki tercihi mümkün olan en erken anda, sayfanın <head> kısmında, herhangi bir CSS boyanmadan önce uygulamaktır.

<head>
  <script>
    (function () {
      const saved = localStorage.getItem("theme");
      if (saved) {
        document.documentElement.setAttribute("data-theme", saved);
      }
    })();
  </script>
  <link rel="stylesheet" href="styles.css">
</head>

Bu küçük satır içi (inline) script, render başlamadan çalıştığı için ekran asla yanlış renkle boyanmaz. Script'i mutlaka stil dosyasından önce ve doğrudan HTML'in içine koy; harici dosyaya alırsan ağ gecikmesi yüzünden flicker geri döner.

Geçişleri yumuşat — ama akıllıca

Tema değişiminde renklerin yumuşak geçmesi hoş durur, ama dikkatli olmak gerekir. transition'ı her şeye uygularsan ilk sayfa açılışında istenmeyen bir animasyon görülebilir. Pratik bir yöntem, geçişi sadece toggle anında devreye sokmaktır: JavaScript geçici bir sınıf ekler, çift requestAnimationFrame sonra kaldırır.

:root.theme-transition,
:root.theme-transition * {
  transition: background-color .2s ease, color .2s ease;
}

Erişilebilirlik için prefers-reduced-motion tercihini de unutma; hareketi azaltmak isteyen kullanıcılarda geçişleri kapat. Ayrıca toggle butonuna aria-label ekle ki ekran okuyucular ne işe yaradığını anlatsın.

Test et ve cilala

  • Kontrast: Karanlık temada metin/zemin kontrastını WCAG AA (en az 4.5:1) seviyesinde tut. Tarayıcı DevTools'un kontrast aracı bunu anında gösterir.
  • Görseller: Şeffaf PNG logolar karanlık zeminde kaybolabilir; gerekirse karanlık tema için ayrı bir varyant göster.
  • Gölgeler: Karanlık temada kutu gölgeleri neredeyse görünmez. Derinlik hissini gölge yerine hafif açık yüzey renkleriyle ver.
  • theme-color: Mobilde tarayıcı çubuğunun rengini <meta name="theme-color"> ile temaya uydur.

Sık Sorulan Sorular

prefers-color-scheme tüm tarayıcılarda çalışıyor mu?

Evet, güncel tüm büyük tarayıcılar (Chrome, Firefox, Safari, Edge) yıllardır destekliyor. Çok eski bir tarayıcıda medya sorgusu basitçe görmezden gelinir ve kullanıcı varsayılan (aydınlık) temayı görür; yani güvenli bir şekilde "progressive enhancement" olarak çalışır.

Tercihi neden cookie değil de localStorage'da tutuyorum?

Tema tamamen istemci tarafı bir görsel tercihtir; sunucuya gönderilmesi gerekmez. localStorage senkron okunur, böylece <head> içindeki inline script onu anında alıp flicker'ı önler. Sunucu tarafı render edilen bir tema istiyorsan cookie kullanmak mantıklı olur, çünkü cookie isteğe eklenir.

Sadece prefers-color-scheme yetmez mi, toggle şart mı?

Şart değil ama önerilir. Bazı kullanıcılar cihazını karanlık ayarlar ama belli siteleri aydınlık okumak ister (ya da tersi). Manuel toggle bu kontrolü onlara verir ve memnuniyeti artırır.

Temiz, flicker'sız bir karanlık tema hem şık görünür hem de kullanıcıların gözünü korur. Sitende dark mode kurmak, mevcut renk sistemini değişkenlere taşımak ya da tema geçişlerini düzeltmek istersen benimle iletişime geç — birlikte hızlıca hayata geçirelim.

Bu kategorideki tüm yazılar →

Devamı için