CSS ile dark mode yapmanın üç temel aracı vardır: Kullanıcının açık mı koyu tema mı istediğini okuyan prefers-color-scheme medya özelliği, bir öğenin hangi renk şemalarında rahatça gösterilebileceğini tarayıcıya bildiren color-scheme özelliği ve etkin şemaya göre iki renkten birini döndüren light-dark() fonksiyonu. En kısa çalışan çözüm, :root üzerinde color-scheme: light dark tanımlayıp renkleri light-dark(açık, koyu) biçiminde yazmaktır.

Bu yazıda üç aracın ne yaptığını ve birbirinden farkını, tarayıcının kendi çizdiği arayüz parçalarının (form denetimleri, kaydırma çubukları, sayfa zemini) nasıl uyum sağladığını, sistem renklerini, Windows yüksek kontrast modu gibi zorlanmış renk modlarını ve sık yapılan hataları MDN belgelerine dayanarak anlatıyoruz. Renk değerlerinin kendisi (hex, rgb, oklch) CSS renk değerleri yazısında ele alınıyor.

prefers-color-scheme: kullanıcının tercihini okumak

prefers-color-scheme, kullanıcının işletim sistemi ya da tarayıcı ayarı üzerinden açık veya koyu tema isteyip istemediğini algılayan bir medya özelliğidir. İki değeri vardır. dark kullanıcının koyu temayı tercih ettiğini bildirir. light ise kullanıcının açık temayı tercih ettiğini ya da hiçbir tercih bildirmediğini gösterir. Bu ayrıntı önemlidir: Tercihi olmayan bir kullanıcı da light sorgusuyla eşleşir.

MDN'nin önerdiği yaygın düzen, varsayılan olarak açık renkleri yazmak ve (prefers-color-scheme: dark) sorgusuyla koyu sürüme geçmektir. Tersini yapmak da mümkündür: Koyu varsayılanı yazıp (prefers-color-scheme: light) ile açık sürüme geçebilirsiniz.

css
.tema-a {
  background: #ddccaa;
  color: #773311;
}

@media (prefers-color-scheme: dark) {
  .tema-a {
    background: #775533;
    color: #ddccbb;
  }
}
/* sonuç: kullanıcı koyu tema istiyorsa kahverengi tonlar koyulaşır,
   aksi hâlde açık tonlar kalır */

Media query sözdiziminin geri kalanı, örneğin and ve not ile birleştirme, media query yazısında anlatılıyor. MDN ayrıca bu tercihin Sec-CH-Prefers-Color-Scheme adlı bir HTTP istemci ipucu (client hint) olarak sunucuya da iletilebildiğini belirtir; böylece sunucu tarafında şemaya göre hazırlanmış içerik gönderilebilir.

color-scheme: tarayıcının kendi arayüzünü uyarlamak

color-scheme: tarayıcının kendi arayüzünü uyarlamak: normal, light, dark, light dark

color-scheme özelliği bir öğenin hangi renk şemalarında rahatça işlenebileceğini belirtir. MDN'ye göre tarayıcı bu bilgiye göre şu parçaları kullanılan şemaya uyarlar: tuval (canvas) yüzeyinin rengi, kaydırma çubuklarının ve diğer etkileşim arayüzünün varsayılan renkleri, form denetimlerinin varsayılan renkleri ve yazım denetimi alt çizgileri gibi tarayıcının sağladığı diğer arayüz öğeleri. Sistem renklerinin kullanılan değerleri de şemaya göre değişir.

Bu listede sizin yazdığınız öğelerin renkleri yoktur. MDN bunu açıkça söyler: Bileşen yazarlarının geri kalan öğelerde renk şemalarını desteklemek için prefers-color-scheme kullanması gerekir. Yani color-scheme: dark yazmak tek başına sayfanızı koyulaştırmaz; yalnızca tarayıcının çizdiği parçaları ve sistem renklerini koyu şemaya geçirir. Kendi renklerinizi ayrıca tanımlamalısınız.

DeğerAnlamı
normalÖğe sayfanın renk şeması ayarlarıyla işlenir; ayar yoksa varsayılan renkler kullanılır
lightÖğe işletim sisteminin açık şemasıyla işlenebilir
darkÖğe işletim sisteminin koyu şemasıyla işlenebilir
light darkÖğe iki şemayı da destekler; kullanıcının tercihi seçilir
only light / only darkTarayıcının bu öğe için renk şemasını kendiliğinden değiştirmesini yasaklar
css
:root {
  color-scheme: light dark;
}

header {
  color-scheme: only light;
}

footer {
  color-scheme: only dark;
}

Sayfanın tamamını kullanıcının tercihine açmak için color-scheme değerini :root üzerinde tanımlarsınız. Belirli öğeleri farklı bir şemaya almak için o öğelere ayrı değer verebilirsiniz. only anahtar kelimesi tarayıcının o öğe için renkleri kendi başına geçersiz kılmasını engeller; MDN bunu Chrome'un otomatik koyu tema özelliğinin yaptığı renk değişikliklerini kapatmanın bir yolu olarak örnekler.

MDN'nin bu özellikle ilgili bir önerisi daha var: CSS'e ek olarak belgenin <head> bölümüne, herhangi bir stil bilgisinden önce <meta name="color-scheme"> etiketini eklemek. Bu etiket tarayıcıya tercih edilen renk şemasını sayfa yüklenirken bildirir ve istenmeyen ekran parlamalarını önlemeye yardımcı olur. CSS dosyası henüz inmeden tarayıcı beyaz bir zemin çizerse koyu tema kullanan bir ziyaretçi kısa bir beyaz parlama görebilir.

html
<meta name="color-scheme" content="light dark" />

light-dark(): iki rengi tek bildirimde yazmak

light-dark() fonksiyonu iki renk ya da iki görsel alır ve etkin renk şemasına göre birini döndürür. Kullanılan şema light ise ya da hiçbir tercih belirtilmemişse ilk değeri, şema dark ise ikinci değeri verir. Böylece her renk için ayrı bir media query bloğu yazmanız gerekmez.

css
:root {
  color-scheme: light dark;
}

body {
  color: light-dark(#333b3c, #efefec);
  background-color: light-dark(#efedea, #223a2c);
}
/* sonuç: açık şemada koyu gri metin ve açık zemin,
   koyu şemada açık metin ve koyu yeşilimsi zemin */

MDN'ye göre fonksiyonun çalışması için color-scheme değerinin light dark olması gerekir ve bu değer genellikle :root üzerinde tanımlanır. Fonksiyon şemayı doğrudan kullanıcı tercihinden değil, öğenin kullanılan renk şemasından okur. Bu yüzden bir bölüme color-scheme: light ya da color-scheme: dark verdiğinizde o bölümdeki light-dark() değerleri o şemaya zorlanır. MDN bu tekniği gösterim amacıyla kullanır ama bir uyarı ekler: Kullanıcı bir tercih yapmışsa genellikle bu tercihi geçersiz kılmamalısınız.

İkinci biçim görseller içindir: light-dark(url("light-icon.png"), url("dark-icon.png")) ya da iki linear-gradient() değeri yazabilirsiniz. Görsel biçiminde none anahtar kelimesi tamamen saydam, doğal boyutu olmayan bir görsel üretir. Görsel desteği renk desteğinden ayrı gelmiş olabileceği için MDN'nin kendi örneği de bunu @supports (background-image: light-dark(url("light.png"), url("dark.png"))) ile sınar. Özellik sorgularını @supports yazısında anlatıyoruz.

Özel özelliklerle tema yönetimi

Gerçek bir sitede onlarca renk vardır. Bunları tek tek light-dark() içine yazmak yerine renkleri özel özelliklerde (CSS değişkenlerinde) toplamak bakımı kolaylaştırır. MDN'nin light-dark() örneği de açık ve koyu renkleri :root üzerinde değişken olarak tanımlayıp fonksiyona var() ile verir.

css
:root {
  color-scheme: light dark;

  --light-bg: ghostwhite;
  --light-color: darkslategray;
  --light-code: tomato;

  --dark-bg: darkslategray;
  --dark-color: ghostwhite;
  --dark-code: gold;
}

body {
  background-color: light-dark(var(--light-bg), var(--dark-bg));
  color: light-dark(var(--light-color), var(--dark-color));
}

code {
  color: light-dark(var(--light-code), var(--dark-code));
}

Alternatif yaklaşım, anlamsal değişkenler tanımlayıp yalnızca değerlerini media query içinde değiştirmektir: --zemin ve --metin gibi adlar verirsiniz, bileşenler hep bu adları kullanır, (prefers-color-scheme: dark) bloğu ise yalnızca değişkenlerin değerini günceller. İki yaklaşım da geçerlidir. Değişkenlerin devralınma ve yedek değer davranışı CSS değişkenleri yazısında anlatılıyor.

css
:root {
  color-scheme: light dark;
  --zemin: #ffffff;
  --metin: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --zemin: #121212;
    --metin: #eeeeee;
  }
}

body {
  background-color: var(--zemin);
  color: var(--metin);
}

Sistem renkleri: Canvas, CanvasText ve diğerleri

Sistem renkleri: Canvas, CanvasText ve diğerleri: Canvas / CanvasText, LinkText / VisitedText / ActiveText, ButtonFace / ButtonText / ButtonBorder, Field / FieldText

<system-color> veri türü, bir sayfanın farklı parçaları için genellikle varsayılan renk seçimlerini yansıtan anahtar kelimelerden oluşur ve bir <color> değerinin kullanılabildiği her yerde kullanılabilir. Anahtar kelimeler büyük küçük harfe duyarlı değildir. color-scheme sayfasına göre sistem renklerinin kullanılan değerleri seçilen şemaya uyum sağlar; bu yüzden sistem renkleriyle yazılmış bir bileşen ek kural gerektirmeden açık ve koyu şemaya uyabilir.

Anahtar kelimeKullanım yeri
Canvas / CanvasTextUygulama içeriğinin ya da belgenin zemini / metni
LinkText / VisitedText / ActiveTextZiyaret edilmemiş / ziyaret edilmiş / etkin bağlantı metni
ButtonFace / ButtonText / ButtonBorderDenetimlerin zemini / metni / kenarlığı
Field / FieldTextGiriş alanlarının zemini / metni
Highlight / HighlightTextSeçili öğelerin zemini / metni
AccentColor / AccentColorTextVurgulu arayüz denetimlerinin zemini / metni
GrayTextDevre dışı öğelerin metni
Mark / MarkTextmark öğesi gibi özel işaretlenmiş metnin zemini / metni
css
.panel {
  background-color: Canvas;
  color: CanvasText;
  border: 1px solid ButtonBorder;
}
/* sonuç: renkler kullanılan renk şemasına ve sistem ayarlarına göre belirlenir */

MDN iki uyarı ekler. Birincisi, parmak izi riskini azaltmak için bazı tarayıcılar AccentColor ve AccentColorText için belirli durumlar dışında sabit bir değer döndürür. İkincisi, ActiveBorder, ButtonHighlight ve CaptionText gibi eski sistem rengi anahtar kelimeleri herkese açık sayfalarda kullanım için kullanımdan kaldırılmıştır ve her birinin önerilen bir karşılığı vardır; örneğin CaptionText yerine CanvasText.

Zorlanmış renk modu: forced-colors

Bazı kullanıcılar Windows yüksek kontrast modu gibi, renkleri kullanıcı ve tarayıcı tarafından belirlenen sınırlı bir palete indiren bir erişilebilirlik özelliği kullanır. Bunu @media (forced-colors: active) ile algılayabilirsiniz. MDN'ye göre bu modda color, background-color, border-color, outline-color gibi özelliklerin yazar değerleri yokmuş gibi davranılır ve tarayıcının sistem renklerinden seçtiği değerler kullanılır. Ayrıca box-shadow ve text-shadow none değerine, color-scheme ise light dark değerine zorlanır.

Bu modda tarayıcı, Canvas sistem renginin açıklığına bakarak uygun prefers-color-scheme değerini de tetikler. MDN, zorlanan özelliklerin dışında kalan yerlerde sistem renklerinin kullanılmasını önerir; böylece sayfanın bütünü aynı paleti kullanır. Örneğin bilgi taşıyan bir gölgeyi bu modda kenarlıkla değiştirmek akıllıca olur.

css
@media (forced-colors: active) {
  .kart {
    border: 1px solid CanvasText;
    /* box-shadow bu modda none olur, kenarlık sınırı görünür tutar */
  }
}

Gömülü SVG ve iframe öğelerinde renk şeması

MDN'ye göre <img> ile gömülen bir SVG ya da bir iframe içindeki belge, prefers-color-scheme sorgusunu kendisini barındıran öğenin color-scheme değerine göre değerlendirir. SVG'nin satır içi değil, örneğin <img src="circle.svg"> ile gömülmüş olması gerekir. Bu sayede ebeveyni color-scheme: dark olan bir kutudaki ikon, kendi stil bloğundaki koyu tema kuralını kullanır. Bu kullanım farklı kökenden gelen SVG ve iframe öğelerinde de izinlidir.

Uygulamalı mini örnek: üç adımda dark mode

Aşağıdaki örnek bir blog sayfasını hem kullanıcının tercihine uyan hem de form denetimleri ve kaydırma çubuklarıyla tutarlı hâle getirir.

css
/* 1. Sayfa iki şemayı da destekliyor */
:root {
  color-scheme: light dark;
  --acik-vurgu: #0b57d0;
  --koyu-vurgu: #a8c7fa;
}

/* 2. Zemin ve metin şemaya göre */
body {
  background-color: light-dark(#ffffff, #121212);
  color: light-dark(#1f1f1f, #e3e3e3);
}

a {
  color: light-dark(var(--acik-vurgu), var(--koyu-vurgu));
}

.kart {
  box-shadow: 0 2px 6px rgb(0 0 0 / 0.3);
}

/* 3. Zorlanmış renk modunda gölge yerine kenarlık */
@media (forced-colors: active) {
  .kart {
    border: 1px solid CanvasText;
  }
}
/* sonuç: açık şemada beyaz zemin ve mavi bağlantı,
   koyu şemada koyu zemin ve açık mavi bağlantı;
   input, select ve kaydırma çubukları color-scheme sayesinde uyum sağlar;
   zorlanmış renk modunda kartın sınırı kenarlıkla görünür kalır */

İlk adım tarayıcıya iki şemayı da desteklediğimizi söyler; bu hem tarayıcının çizdiği parçaları uyarlar hem de light-dark() fonksiyonunu etkinleştirir. İkinci adım kendi renklerimizi tanımlar. Üçüncü adım zorlanmış renk modunu hesaba katar: Bu modda box-shadow none değerine zorlandığı için kartın sınırı kaybolurdu, bu yüzden bir kenarlık ekliyoruz. Kenarlık rengi de bu modda tarayıcının sistem renklerinden birine zorlanabilir, ama kenarlığın kendisi görünür kalır. Vurgu renkleri MDN örneğindeki gibi değişkenlerde tutulup light-dark() içine var() ile verildi; böylece rengi değiştirmek için yalnızca :root üzerindeki iki değeri güncellemek yeter.

Kullanıcıya tema seçtirmek

Birçok site, sistem tercihinin yanında elle tema değiştirme düğmesi de sunar. CSS tarafında bunun en temiz yolu, kök öğeye bir sınıf ya da öznitelik eklendiğinde color-scheme değerini zorlamaktır; light-dark() ile yazılmış tüm renkler buna kendiliğinden uyar. Sınıfı eklemek ve seçimi saklamak JavaScript işidir ve bu serinin kapsamı dışındadır. MDN'nin uyarısını burada da hatırlayın: Varsayılan davranış her zaman kullanıcının sistem tercihine uymak olmalıdır; elle seçim yalnızca kullanıcı bunu bilerek değiştirdiğinde devreye girmelidir.

css
:root {
  color-scheme: light dark;
}

:root.tema-acik {
  color-scheme: light;
}

:root.tema-koyu {
  color-scheme: dark;
}

Sık yapılan hatalar

Sık yapılan hatalar: color-scheme özelliğini unutup light-dark() kullanmak, color-scheme tek başına sayfayı koyulaştırır sanmak, light değerini yalnızca açık tema tercihi sanmak...
  • color-scheme özelliğini unutup light-dark() kullanmak: Fonksiyonun şemaya göre değişmesi için color-scheme: light dark tanımlı olmalıdır.
  • color-scheme tek başına sayfayı koyulaştırır sanmak: Yalnızca tuval, form denetimleri, kaydırma çubukları ve sistem renkleri uyarlanır. Kendi renklerinizi ayrıca yazmalısınız.
  • light değerini yalnızca açık tema tercihi sanmak: Tercih bildirmeyen kullanıcılar da light ile eşleşir.
  • Meta etiketini atlamak: Stil dosyası inene kadar beyaz zemin parlaması görülebilir; <meta name="color-scheme"> etiketini stillerden önce ekleyin.
  • Kullanıcı tercihini zorla ezmek: only light ya da sabit color-scheme: light değerlerini yalnızca gerçekten gerektiğinde kullanın.
  • Zorlanmış renk modunda gölgeye güvenmek: box-shadow bu modda none olur; bilgi taşıyan sınırları kenarlıkla da gösterin.

Sık Sorulan Sorular

prefers-color-scheme mi light-dark() mi kullanmalıyım?

İkisi birlikte de kullanılabilir. light-dark() tek bir değerin iki sürümünü kısa yoldan yazmanızı sağlar. Renk dışındaki değişiklikler (görsel değiştirmek, bir öğeyi gizlemek, kenarlık kalınlığını değiştirmek) için @media (prefers-color-scheme: dark) bloğuna ihtiyaç duyarsınız.

color-scheme özelliğini nereye yazmalıyım?

Sayfanın tamamı için :root üzerine yazın. Yalnızca belirli bölümler farklı bir şemada kalacaksa o bölümlere ayrı değer verin.

Koyu temada form alanları neden hâlâ beyaz görünüyor?

Büyük ihtimalle color-scheme tanımlanmamıştır. Form denetimlerinin varsayılan renkleri bu özellikle uyarlanır; yalnızca prefers-color-scheme ile kendi renklerinizi değiştirmek tarayıcının çizdiği denetimleri etkilemez.

Tailwind gibi bir çatıda da bu yöntem çalışır mı?

Bu yazıdaki özellikler tarayıcının yerel CSS özellikleridir ve hangi çatıyı kullanırsanız kullanın geçerlidir. Tailwind'in kendi karanlık mod araçları için Tailwind rehberine bakabilirsiniz.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: CSS öğrenme rehberi · Media query sözdizimi · CSS renk değerleri · color-mix() ve göreli renkler · CSS değişkenleri · @supports