CSS'te bir renk, <color> veri türüyle ifade edilir ve bu türü yazmanın birden fazla yolu vardır: red gibi adlandırılmış renkler, #ff0099 gibi onaltılık (hex) kodlar, rgb(), hsl(), hwb() gibi sRGB fonksiyonları, lab(), lch(), oklab(), oklch() gibi algıya dayalı renk uzayı fonksiyonları ve özel bir renk uzayı seçmenizi sağlayan color(). Bunların hepsi aynı yere yazılabilir; color, background-color, border-color ya da box-shadow içinde birbirinin yerine kullanılır.

Bu yazıda her yazım biçiminin sözdizimini, bileşenlerinin hangi aralıkta değer aldığını, saydamlık (alpha) kanalının nasıl eklendiğini, currentColor ve transparent anahtar kelimelerinin ne işe yaradığını ve hangi durumda hangi biçimi seçmenin mantıklı olduğunu MDN belgelerine dayanarak anlatıyoruz. Var olan bir rengi karıştırmak ya da ondan açık, koyu veya yarı saydam bir ton türetmek ayrı bir konudur ve color-mix() ve göreceli renkler yazısında işleniyor. Açık ve koyu tema için iki renk tanımlayan light-dark() ise karanlık mod yazısının konusu.

Renk modeli ve renk uzayı ne demek?

Renk modeli ve renk uzayı ne demek?

MDN'nin renk değerleri rehberi iki kavramı ayırır. Renk modeli, renkleri sayılarla temsil eden matematiksel yöntemdir: kırmızı, yeşil ve mavi miktarı (RGB) ya da ton, doygunluk ve açıklık (HSL) gibi. Renk uzayı ise bu modelle hangi renklerin üretilebileceğini tutarlı biçimde tanımlayan sistemdir. Web'in ilk renk modeli RGB'dir ve CSS'teki adlandırılmış renkler, hex kodlar, rgb(), hsl() ve hwb() hep aynı uzayda, yani sRGB'de çalışır.

Bunun pratik anlamı şudur: #ff0000, rgb(255 0 0), hsl(0 100% 50%) ve red aynı kırmızıyı farklı biçimlerde yazar. Fark, rengi düşünme biçiminizdedir. CIELAB ve Oklab tabanlı fonksiyonlar ise insanın algıladığı açıklığa göre tasarlanmıştır ve sRGB'nin dışında kalan, daha geniş gamlı ekranların gösterebildiği renkleri de ifade edebilir. MDN ayrıca renklerin kesin tanımlansa bile kalibre edilmemiş cihazlarda farklı görünebileceğini not eder; aynı değer her ekranda birebir aynı görünmeyebilir.

Adlandırılmış renkler, transparent ve currentColor

En kolay yol bir anahtar kelime yazmaktır: red, teal, rebeccapurple, lightseagreen. MDN'ye göre 160'ın üzerinde adlandırılmış renk vardır, hepsi sRGB uzayındadır, büyük küçük harf ayrımı yapmaz ve hepsi saydamlığı olmayan düz renklerdir. Bazı adlar birbirinin eş anlamlısıdır: aqua ile cyan, fuchsia ile magenta, gray ile grey aynı rengi verir. Adların bir mantığı yoktur; çoğu tarihsel olarak X11 sisteminden alınmıştır, bu yüzden adın çağrıştırdığı tonla gerçek değer her zaman örtüşmez.

İki anahtar kelime özel bir yere sahiptir. transparent tamamen saydam bir renktir. CSS 2.1'de yalnızca background ve border içinde kullanılabilen bir özel değerdi; saydamlık kanalı CSS Colors Level 3 ile geldikten sonra gerçek bir renk olarak yeniden tanımlandı ve artık <color> kabul eden her yerde geçerli. MDN, gradyanlarda beklenmedik koyulaşmayı önlemek için belirtimin transparent değerini alpha ile önceden çarpılmış (premultiplied) uzayda hesaplamayı istediğini, eski tarayıcıların ise onu alpha değeri sıfır olan siyah gibi ele alabileceğini belirtir.

currentColor ise öğenin color özelliğinin o anki değerini temsil eder. Böylece metin rengini, varsayılan olarak bu değeri almayan özelliklerde de kullanabilirsiniz. Üstelik border-color gibi bazı renk özellikleri zaten varsayılan olarak bu değeri kullanır. currentColor doğrudan color özelliğine yazılırsa kendine başvuramayacağı için kalıtımla gelen color değerini alır, yani inherit gibi davranır.

css
.uyari {
  color: teal;
  border: 1px dashed currentColor;
  /* kenarlık da teal olur */
}

.uyari .cizgi {
  height: 4px;
  background: currentColor;
  /* teal kalıtımla gelir, çizgi metinle aynı renkte */
}

.uyari.kirmizi {
  color: red;
  /* yalnızca color değişti; kenarlık ve çizgi de kırmızıya döner */
}

Bu desenin asıl faydası son kuralda görünür: Rengi tek bir yerde değiştirdiğinizde ona bağlı kenarlık, gölge ya da çizgi de kendiliğinden güncellenir. Aynı fikri birden fazla renkle uygulamak istediğinizde CSS değişkenleri daha esnek bir araçtır.

Hex renk kodları: #RGB, #RRGGBB ve alpha

Hex yazım # işaretiyle başlar ve kırmızı, yeşil, mavi bileşenlerini onaltılık sayılarla verir. Dört biçimi vardır: #RGB, #RGBA, #RRGGBB ve #RRGGBBAA. İki haneli her bileşen 00 ile ff (0 ile 255) arasındadır. Tek haneli kısa yazımda her hane ikiye katlanır; #f09 aslında #ff0099 demektir. Yazım büyük küçük harfe duyarlı değildir: #00ff00 ile #00FF00 aynıdır. MDN bir kısıtı da vurgular: Bütün bileşenler aynı hane sayısıyla yazılmalıdır; kısa ve uzun biçimi aynı kodda karıştıramazsınız.

Dördüncü (ya da sekiz haneli yazımda dördüncü çift) bileşen alpha kanalıdır: 0 veya 00 tamamen saydam, f veya ff tamamen opaktır. Değer küçüldükçe renk daha saydam görünür. Hex kodları ondalık sayıya çevirmek için her çifti 16 tabanında okursunuz.

css
.a { color: #008080; }
/* 00 = 0, 80 = 8 x 16 = 128, 80 = 128
   yani rgb(0 128 128); MDN tablosunda teal ile aynı değer */

.b { color: #f09; }
/* kısa yazım: #ff0099 = rgb(255 0 153) */

.c { background-color: #ff000080; }
/* alpha: 80 = 128, 128 / 255 = yaklaşık 0,502
   yani yaklaşık yüzde 50 opak kırmızı */

Bu hesapta dikkat edilecek nokta, alpha çiftinin yüzde değil 0 ile 255 arasında bir sayı olmasıdır. Tam yüzde 50 elde etmek mümkün değildir çünkü 255 tek sayıdır; 80 (128) yüzde 50'nin biraz üstünde, 7f (127) biraz altında kalır. Saydamlığı yüzde olarak düşünmek istiyorsanız fonksiyon yazımı daha okunaklıdır.

rgb() fonksiyonu ve modern boşluklu sözdizimi

rgb() aynı sRGB rengini fonksiyon olarak yazar: rgb(R G B) ya da saydamlıkla rgb(R G B / A). Her renk bileşeni 0 ile 255 arasında bir sayı, yüzde 0 ile yüzde 100 arasında bir yüzde ya da eksik bileşen anlamına gelen none anahtar kelimesi olabilir. Alpha değeri eğik çizgiden sonra gelir; 0 ile 1 arasında bir sayı veya yüzde olarak yazılır ve verilmezse yüzde 100 kabul edilir. Örneğin yarı opak parlak kırmızı rgb(255 0 0 / 50%) ya da rgb(100% 0 0 / 0.5) şeklinde yazılabilir.

Eski projelerde virgüllü yazımı ve rgba() fonksiyonunu sık görürsünüz. MDN'ye göre rgba() artık rgb() için bir takma addır, ikisi tamamen eşdeğerdir ve rgb() kullanılması önerilir. Virgüllü eski biçim (rgb(0, 255, 255)) hâlâ geçerlidir ancak none değeri yalnızca boşluklu yazımda kullanılabilir. Bir ayrıntı daha: JavaScript ile hesaplanmış stili okuduğunuzda tarayıcı rengi uyumluluk nedeniyle virgüllü eski biçimde, alpha 1 ise rgb(), değilse rgba() olarak döndürür.

css
.kutu {
  color: rgb(31 120 50);
  background-color: rgb(255 122 127 / 20%);
  /* yüzde 20 opak pembe zemin */
  border-color: rgb(0 0 0 / 0.4);
}

.eski-yazim {
  color: rgb(0, 255, 255);
  /* geçerli, ama yeni kodda boşluklu biçim tercih edilir */
}

hsl() ve hwb(): ton tabanlı sRGB renkleri

hsl() rengi ton (hue), doygunluk (saturation) ve açıklık (lightness) ile tanımlar: hsl(H S L / A). Ton bir açıdır; birimsiz sayı da yazılabilir ve derece kabul edilir. Doygunlukta yüzde 100 tam doygun, yüzde 0 gridir. Açıklıkta yüzde 100 beyaz, yüzde 0 siyah, yüzde 50 ise "normal" renktir. MDN'nin rehberine göre bu fonksiyon tarayıcılarda desteklenen ilk ton tabanlı renk fonksiyonudur ve rgb()'ye göre daha sezgiseldir, çünkü tonu, doygunluğu ve açıklığı ayrı ayrı oynatmanın etkisini tahmin etmek kırmızı, yeşil, mavi oranlarını değiştirmekten kolaydır.

Tümleyen renk bulmak da açı üzerinden basit bir işlemdir: Renk çemberinde aynı çap üzerinde durduklarından tona 180 derece eklemek veya çıkarmak yeterlidir. Tonu 10deg olan bir rengin tümleyeni 190deg tonundadır. hsla() da rgba() gibi bir takma addır.

hwb() aynı sRGB uzayında, aynı ton açılarıyla çalışır ama doygunluk ve açıklık yerine beyazlık (whiteness) ve siyahlık (blackness) ekler. MDN iki kuralı açıkça verir: Her ton için hwb(H 0% 0%) ile hsl(H 100% 50%) aynı renktir. Beyazlık ile siyahlığın toplamı yüzde 100 veya daha fazlaysa sonuç bir gri tonudur; toplam yüzde 100'ü aşarsa iki değer orantılı olarak normalleştirilir.

css
.ton-ornekleri {
  --ana: hsl(210 80% 45%);
  /* mavi tonu */
  --tumleyen: hsl(30 80% 45%);
  /* 210 + 180 = 390, 390 - 360 = 30 derece */
  --soluk: hsl(210 20% 45%);
  /* aynı ton, daha az doygun */
  --doygun: hwb(210 0% 0%);
  /* hsl(210 100% 50%) ile aynı renk */
  --gri: hwb(210 60% 60%);
  /* 60 + 60 = 120, yüzde 100 üstü: gri tonu */
}

Son satırdaki normalleştirme şöyle işler: Beyazlık 60 / 120 = 0,5 ve siyahlık 60 / 120 = 0,5 olarak yeniden ölçeklenir, yani renk eşit oranda beyaz ve siyahtan oluşan bir gri olur. Ton değeri bu durumda görünür sonucu etkilemez.

HSL'nin zayıf noktası ve algısal renk uzayları

HSL'nin zayıf noktası ve algısal renk uzayları: lab(), lch(), oklab(), oklch()

MDN, hsl() ve hwb() için önemli bir sınırlamaya dikkat çeker: Bu fonksiyonlarda tam doygun her ton aynı "açıklığa" sahipmiş gibi yazılır, ama insan gözü böyle algılamaz. Tam doygun mavi (hsl(240deg 100% 50%)) üzerine beyaz metin okunabilirken aynı açıklıktaki tam doygun sarı (hsl(60deg 100% 50%)) üzerine beyaz metin okunmaz hâle gelir. Çünkü HSL'deki açıklık diğer renklere göre göreli bir değerdir, algıya göre değil.

CIELAB ve Oklab renk uzayları bu sorunu çözmek için tasarlanmıştır. MDN'ye göre bu uzaylar insanın görebildiği renklerin tamamını kapsar ve tekdüzedir: İki nokta arasındaki belirli bir mesafe, uzayın her yerinde gözle aşağı yukarı aynı farkı yaratır. Oklab, CIELAB ile aynı model türünü kullanır ama ek sayısal iyileştirmelerden geçtiği için daha doğru kabul edilir ve tonları algısal olarak daha tekdüzedir. CIELAB tarafında lab() ve lch(), Oklab tarafında oklab() ve oklch() bulunur.

FonksiyonUzayBileşenlerAçıklık aralığı
lab()CIELABL, a (yeşil/kırmızı), b (mavi/sarı)0 ile 100 ya da yüzde
lch()CIELABL, C (kroma), H (ton)0 ile 100 ya da yüzde
oklab()OklabL, a, b0 ile 1 ya da yüzde
oklch()OklabL, C (kroma), H (ton)0 ile 1 ya da yüzde

lab() ve oklab() dikdörtgen koordinat kullanır: a ekseni rengin yeşile mi kırmızıya mı yakın olduğunu, b ekseni maviye mi sarıya mı yakın olduğunu söyler. lab() için bu değerler yaklaşık -125 ile 125, oklab() için -0,4 ile 0,4 arasındadır; belirtime göre sınırsızdır ama pratikte sırasıyla ±160 ve ±0,5'i aşmaz. lch() ve oklch() ise kutupsal biçimdir: aynı açıklık eksenini kullanır ama renk miktarını kroma (C), yönünü ton açısı (H) ile verir.

oklch() pratikte nasıl okunur?

oklch(L C H / A) yazımında L algılanan açıklıktır: 0 veya yüzde 0 siyah, 1 veya yüzde 100 beyazdır. MDN bu açıklığın HSL'deki L ile aynı şey olmadığını özellikle not eder; burada kastedilen gözün gördüğü parlaklıktır. C kromadır, kabaca "ne kadar renk" olduğunu söyler; en küçük anlamlı değer 0'dır, üst sınır teorik olarak yoktur ama pratikte 0,5'i geçmez. H ton açısıdır.

Burada bir tuzak var. Genellikle CSS'te yüzde 100 sayısal 1'e denktir, ama oklch()'nin kroma bileşeninde yüzde 100, 0.4 anlamına gelir. lch()'de ise açıklık için yüzde 100 = 100, kroma için yüzde 100 = 150'dir. İkinci tuzak ton açılarıdır: Aynı açı sRGB (hsl(), hwb()), CIELAB (lch()) ve Oklab (oklch()) uzaylarında farklı tonlara karşılık gelir. hsl()'de kırmızıya denk gelen açıyı oklch()'ye kopyaladığınızda aynı kırmızıyı elde etmezsiniz.

css
.palet {
  --mavi: oklch(55% 0.15 250);
  --mavi-acik: oklch(75% 0.15 250);
  /* yalnızca algılanan açıklık değişti */
  --mavi-yari: oklch(55% 0.15 250 / 0.5);
  /* aynı renk, yüzde 50 opak */
  --kroma-yuzde: oklch(55% 50% 250);
  /* kroma: yüzde 50 = 0.4 x 0.5 = 0.2 */
}

Bir paletin tonlarını üretirken oklch()'nin avantajı, açıklık değerini değiştirdiğinizde ton algısının görece sabit kalmasıdır. Bu, renk tutarlılığını HSL'ye göre daha öngörülebilir kılar. Yine de her açıklık ve kroma bileşimi sRGB içinde gösterilemeyebilir; değerleri tarayıcının renk seçicisinde deneyerek kontrol etmek en güvenli yoldur.

color() ve geniş gamlı renkler

Diğer fonksiyonların çoğu örtük olarak sRGB'de çalışırken color() renk uzayını açıkça belirtmenizi sağlar: color(uzay c1 c2 c3 / A). Önceden tanımlı uzaylar srgb, srgb-linear, display-p3, display-p3-linear, a98-rgb, prophoto-rgb, rec2020, xyz, xyz-d50 ve xyz-d65'tir. Sayısal değerlerde genellikle 0 ile 1 arası uzayın sınırlarıdır; dışındaki değerler yazılabilir ama o uzayın gamı dışında kalır.

MDN'nin örneğinde önce sRGB bir değer verilir, ardından ekran geniş gamı destekliyorsa daha canlı bir renk kullanılır. Ekranın bu gamı destekleyip desteklemediği color-gamut medya özelliğiyle sınanır. @media sözdiziminin kendisi media query yazısında anlatılıyor.

css
.canli {
  background-color: color(srgb 0 0 1);
}

@media (color-gamut: p3) {
  .canli {
    background-color: color(display-p3 0 0 1);
    /* sRGB gamının dışındaki daha canlı mavi */
  }
}

Eksik bileşen: none anahtar kelimesi

Virgüllü eski yazım dışında, renk fonksiyonlarının her bileşeni none olarak yazılabilir. MDN bunu "eksik bileşen" olarak tanımlar. Gradyan, geçiş ya da animasyon gibi enterpolasyon dışındaki her durumda eksik bileşen sıfır gibi davranır: oklab(50% none -0.25) ile oklab(50% 0 -0.25) aynıdır, hsl(none 100% 50%) ile hsl(0deg 100% 50%) aynıdır. Fark enterpolasyon sırasında ortaya çıkar: Bir renkte eksik olan bileşen, diğer rengin aynı bileşeniyle doldurulur. Bu sayede örneğin yalnızca açıklığı değiştirip tonu sabit tutan bir geçiş yazabilirsiniz. Enterpolasyonun varsayılan olarak Oklab uzayında yapıldığını ve bunun nasıl değiştirildiğini color-mix() yazısında ve gradyan yazısında göreceksiniz.

Alpha kanalı ile opacity arasındaki fark

Saydamlık iki farklı yoldan verilebilir ve sonuçları aynı değildir. Renk değerindeki alpha kanalı yalnızca o rengi etkiler: background: rgb(0 0 0 / 40%) yazdığınızda yalnızca zemin yarı saydam olur, metin tam opak kalır. opacity özelliği ise MDN'nin anlatımıyla öğeye bir bütün olarak, içeriğiyle birlikte uygulanır. Değer alt öğelere kalıtımla geçmez ama öğe ve tüm çocukları arka plana göre aynı saydamlıkta görünür. MDN, yalnızca arka planı saydam yapmak istiyorsanız alpha kanallı bir renk kullanmanızı önerir.

opacity'nin iki yan etkisi daha vardır. 1 dışındaki bir değer öğe için yeni bir istifleme bağlamı (stacking context) oluşturur; bunun z-index üzerindeki etkisini z-index yazısında bulabilirsiniz. Ayrıca opacity: 0 öğeyi görünmez yapar ama işaretçi olaylarını almaya ve sekme sırasındaysa odaklanmaya devam eder.

css
.kart-a {
  background-color: rgb(0 0 0 / 40%);
  color: white;
  /* yalnızca zemin yarı saydam, metin tam opak */
}

.kart-b {
  background-color: black;
  color: white;
  opacity: 0.4;
  /* zemin, metin ve tüm alt öğeler birlikte saydamlaşır */
}

Hangi biçimi ne zaman seçmeli?

Hangi biçimi ne zaman seçmeli? Hızlı deneme, örnek kod, Tasarım aracından gelen değer, Kanal bazında saydamlık, Ton ve açıklıkla düşünmek
İhtiyaçUygun yazımNeden
Hızlı deneme, örnek kodAdlandırılmış renkOkunaklı ama seçenek sınırlı
Tasarım aracından gelen değerHexÇoğu araç hex verir, kısa ve yaygın
Kanal bazında saydamlıkrgb() / AAlpha yüzde ya da sayı olarak okunaklı
Ton ve açıklıkla düşünmekhsl() veya hwb()Sezgisel ama algısal olarak tekdüze değil
Tutarlı açıklıkta paletoklch()Algılanan açıklık sabit kalır
Geniş gamlı ekranlarcolor(display-p3 ...)Uzayı açıkça seçersiniz

Bu tablo bir sıralama değil, kullanım bağlamına göre bir başlangıç noktasıdır. Aynı projede birden fazla biçim kullanmak sorun değildir; önemli olan renkleri tek bir yerde, tercihen özel özellikler içinde toplamaktır.

Sık yapılan hatalar

  • Hex kodda hane sayısını karıştırmak: #ff09 dört haneli #RGBA olarak okunur, yani #ffff0099 anlamına gelir; altı haneli bir renk yazmak istiyorsanız eksik hane renk değiştirir.
  • Boşluklu ve virgüllü yazımı karıştırmak: rgb(255 0 0, 0.5) gibi yarım bir karışım geçersizdir. Ya tamamen boşluklu (/ ile alpha) ya tamamen virgüllü yazın.
  • oklch() kromasında yüzdeyi 1 sanmak: Yüzde 100 kroma 0.4'tür.
  • Ton açısını uzaylar arasında kopyalamak: hsl() ile oklch()'de aynı açı aynı tonu vermez.
  • Arka planı saydamlaştırmak için opacity kullanmak: Metin de soluklaşır; alpha kanallı renk kullanın.
  • Bilgiyi yalnızca renkle vermek: MDN, WCAG 2.2 önerisine atıfla rengin bir mesajı iletmenin tek yolu olmamasını vurgular. Hata durumunu kırmızının yanında bir simge ya da metinle de belirtin.

Sık Sorulan Sorular

rgb() ile rgba() arasında fark var mı?

Hayır. MDN'ye göre rgba(), rgb() için bir takma addır ve ikisi tamamen eşdeğerdir. Saydamlığı rgb(255 0 0 / 0.5) şeklinde doğrudan rgb() içinde verebilirsiniz; önerilen yazım da budur. Aynı durum hsla() ve hsl() için de geçerlidir.

Hex kodda saydamlık nasıl verilir?

Altı haneli kodun sonuna iki hane daha ekleyerek: #RRGGBBAA. 00 tamamen saydam, ff tamamen opaktır. Kısa yazımda dördüncü hane alpha olur, örneğin #f008 değeri #ff000088 ile aynıdır.

oklch() kullanmak için hsl()'yi bırakmam gerekir mi?

Gerekmez; ikisi de geçerli <color> değeridir. oklch() özellikle aynı açıklıkta birden çok ton üretmek ya da metin okunabilirliğini korurken tonu değiştirmek istediğinizde avantaj sağlar. Tarayıcı desteği için MDN sayfasındaki uyumluluk tablosuna bakın.

currentColor ile inherit aynı şey mi?

Tam değil. currentColor herhangi bir renk özelliğinde öğenin kendi color değerini kullanır; örneğin border-color: currentColor. Yalnızca color özelliğinin kendisine yazıldığında kalıtımla gelen değeri alır ve bu durumda inherit gibi davranır. Kalıtımın genel kurallarını cascade ve kalıtım yazısında bulabilirsiniz.

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 · color-mix() ve göreceli renkler · CSS gradyanları · background özellikleri · Karanlık mod ve light-dark() · CSS değişkenleri