Ders 23 / 26
Geçişler (gradient)
Doğrusal ve dairesel renk geçişleri; durak noktalarının çözülme kuralı, ara renklerin hesaplanması ve sert geçişle çizgi üretimi.
İçindekiler
Arka plan katmanları bir dosyadan gelen görsellerle kuruldu. Bir katman dosyasız da üretilebilir: renkler arasında hesaplanmış geçişlerle.
Geçiş (gradient) bir renk değil, bir görseldir. Bu ayrım sonuçlar doğurur:
background-color değerine yazılamaz, background-image değerine yazılır; bir ölçüsü
yoktur ve konulduğu alana göre boyutlanır; background-size, background-position ve
background-repeat ona da uygulanır.
Durak Noktaları
Bir geçiş, renk durak noktalarından (color stop) oluşur. Her durak bir renk ve isteğe bağlı bir konum taşır. Konumlar yazılmadığında bir kurala göre doldurulur: ilk durak %0’a, son durak %100’e yerleşir, aradakiler eşit aralıklarla dağıtılır.
İki durak arasındaki her nokta, iki rengin doğrusal karışımıdır.
// gecis.mjs — renk durak noktalarinin cozulmesi ve ara renklerin hesaplanmasi const hexToRgb = (h) => ({ r: parseInt(h.slice(1,3),16), g: parseInt(h.slice(3,5),16), b: parseInt(h.slice(5,7),16) }); const hex = ({r,g,b}) => "#" + [r,g,b].map(v => Math.round(v).toString(16).padStart(2,"0")).join(""); // yazilmamis durak noktalari, komsu bilinen noktalar arasinda esit dagitilir function duraklariCoz(duraklar) { const k = duraklar.map((d) => ({ ...d })); if (k[0].konum == null) k[0].konum = 0; if (k.at(-1).konum == null) k.at(-1).konum = 100; let i = 0; while (i < k.length) { if (k[i].konum != null) { i++; continue; } let j = i; while (k[j].konum == null) j++; const bas = k[i - 1].konum, son = k[j].konum; const adim = (son - bas) / (j - i + 1); for (let t = i; t < j; t++) k[t].konum = +(bas + adim * (t - i + 1)).toFixed(2); i = j; } // durak noktalari azalamaz: onceki degerin altina duseni yukselt for (let t = 1; t < k.length; t++) if (k[t].konum < k[t-1].konum) k[t].konum = k[t-1].konum; return k; } function araRenk(duraklar, yuzde) { const k = duraklariCoz(duraklar); if (yuzde <= k[0].konum) return k[0].renk; if (yuzde >= k.at(-1).konum) return k.at(-1).renk; for (let i = 1; i < k.length; i++) { if (yuzde <= k[i].konum) { const a = k[i-1], b = k[i]; const t = b.konum === a.konum ? 0 : (yuzde - a.konum) / (b.konum - a.konum); const ca = hexToRgb(a.renk), cb = hexToRgb(b.renk); return hex({ r: ca.r + (cb.r-ca.r)*t, g: ca.g + (cb.g-ca.g)*t, b: ca.b + (cb.b-ca.b)*t }); } } } const A = [{ renk: "#143a52" }, { renk: "#8a9da9" }, { renk: "#ffffff" }]; const B = [{ renk: "#143a52", konum: 0 }, { renk: "#8a9da9", konum: 20 }, { renk: "#ffffff", konum: 100 }]; const C = [{ renk: "#143a52", konum: 0 }, { renk: "#143a52", konum: 50 }, { renk: "#ffffff", konum: 50 }, { renk: "#ffffff", konum: 100 }]; for (const [ad, d] of [["esit dagitim", A], ["elle konumlandirilmis", B], ["sert gecis (cizgi)", C]]) { console.log(`--- ${ad} ---`); console.log("cozulen duraklar:", duraklariCoz(d).map((x) => `${x.renk}@${x.konum}%`).join(" ")); const ornek = [0, 10, 20, 25, 49, 50, 51, 75, 100]; console.log(ornek.map((p) => `${String(p).padStart(3)}%:${araRenk(d, p)}`).join(" ")); console.log(""); } console.log("--- aci yonu (linear-gradient) ---"); for (const [aci, yon] of [[0,"asagidan yukari"],[90,"soldan saga"],[180,"yukaridan asagi"],[270,"sagdan sola"]]) { const rad = (aci - 90) * Math.PI / 180; console.log(`${String(aci).padStart(3)}deg -> ${yon.padEnd(18)} birim vektor (${Math.cos(rad).toFixed(3)}, ${(-Math.sin(rad)).toFixed(3)})`); }
--- esit dagitim --- cozulen duraklar: #143a52@0% #8a9da9@50% #ffffff@100% 0%:#143a52 10%:#2c4e63 20%:#436275 25%:#4f6c7e 49%:#889ba7 50%:#8a9da9 51%:#8c9fab 75%:#c5ced4 100%:#ffffff --- elle konumlandirilmis --- cozulen duraklar: #143a52@0% #8a9da9@20% #ffffff@100% 0%:#143a52 10%:#4f6c7e 20%:#8a9da9 25%:#91a3ae 49%:#b4c1c8 50%:#b6c2c9 51%:#b7c3ca 75%:#dae0e4 100%:#ffffff --- sert gecis (cizgi) --- cozulen duraklar: #143a52@0% #143a52@50% #ffffff@50% #ffffff@100% 0%:#143a52 10%:#143a52 20%:#143a52 25%:#143a52 49%:#143a52 50%:#143a52 51%:#ffffff 75%:#ffffff 100%:#ffffff --- aci yonu (linear-gradient) --- 0deg -> asagidan yukari birim vektor (0.000, 1.000) 90deg -> soldan saga birim vektor (1.000, 0.000) 180deg -> yukaridan asagi birim vektor (0.000, -1.000) 270deg -> sagdan sola birim vektor (-1.000, -0.000)
İlk blok eşit dağıtımı gösteriyor: üç durak yazıldı, ortadaki %50’ye yerleşti. %10
noktasındaki renk #2c4e63, ilk iki durağın beşte bir karışımıdır.
İkinci blok aynı üç rengi farklı konumlarla kullanıyor. Orta durak %20’ye çekildiğinde
geçişin hızı değişiyor: ilk beşte birlik bölümde renk hızla açılıyor, kalan bölümde
yavaşlıyor. %10 noktasında birinci blokta #2c4e63 olan renk, burada #4f6c7e — çok
daha açık.
Sert Geçişle Çizgi Üretmek
Üçüncü blok bir hile gibi görünen ama tanımın doğrudan sonucu olan bir kalıbı gösteriyor. İki durak aynı konuma yazıldığında aralarında karışacak mesafe kalmaz ve geçiş bir kenara dönüşür: %49’da hâlâ koyu, %51’de tam beyaz.
Bu, geçişlerle çizgi, şerit ve dama deseni üretmenin yoludur:
.olcum-cizelgesi { background-image: linear-gradient( to right, var(--cizgi) 0 1px, transparent 1px 100% ); background-repeat: repeat-x; background-size: 120px 100%; }
Bir durağa iki konum yazılması (0 1px) o rengin o aralık boyunca sabit kalmasını
bildirir; iki durak yazmanın kısayoludur.
Üç Geçiş Türü
linear-gradient() — renkler bir doğru boyunca değişir. Yön bir açıyla ya da bir
anahtar sözcükle verilir. Çıktının son bloğu açı ölçümünü veriyor: 0deg yukarı doğru,
açı saat yönünde artıyor. to top yazımı 0deg, to right yazımı 90deg ile aynıdır.
Vektörlerdeki pozitif y yukarıyı gösterir.
radial-gradient() — renkler bir merkezden dışa doğru değişir. Şekil (circle ya da
ellipse), ölçü (closest-side, farthest-corner gibi) ve merkez ayrıca verilebilir.
conic-gradient() — renkler bir merkez çevresinde açıya göre değişir. Dilim
grafiklerinin ve renk çarklarının yazılabildiği tür budur.
Üçünün de repeating- önekli biçimleri vardır; durak dizisini sonuna kadar gidip baştan
başlatırlar.
Şerit Etkisi ve Karışım Uzayı
Geniş bir alanda iki yakın renk arasında yapılan geçişte, renk basamaklarının görünür hâle gelmesi olağandır. Sekiz bitlik kanallarda ara değerler yuvarlanır ve büyük bir alanda aynı değere yuvarlanan komşu bölgeler bir şerit gibi görünür.
Karışımın hangi renk uzayında yapılacağı bildirilebilir:
.zemin { background-image: linear-gradient(in oklab, #143a52, #8a5b00); }
Uzay bildirilmediğinde karışım sRGB uzayında yapılır. Algısal olarak düzgün bir uzayda yapılan karışım, iki renk arasındaki ara tonların soluklaşmasını azaltır — özellikle tamamlayıcı renkler arasındaki geçişlerde görülür bir farktır.
Bu yazımın tanınıp tanınmadığı sınanabilir ve tanınmadığında öncesindeki bildirim yerinde kalır:
.zemin { background-image: linear-gradient(#143a52, #8a5b00); } @supports (background-image: linear-gradient(in oklab, red, blue)) { .zemin { background-image: linear-gradient(in oklab, #143a52, #8a5b00); } }
Geçişler Bir Görseldir
Bu dersin başındaki ayrımın pratik sonuçları vardır.
Bir geçiş background-image katmanıdır; birden çok geçiş virgülle üst üste konabilir ve
saydam bölgeler alttaki katmanı gösterir.
Bir geçişin doğal ölçüsü yoktur; background-size verilmediğinde konulduğu alanı doldurur.
Verildiğinde ise background-repeat ile döşenebilir — yukarıdaki çizgi örneği buna dayanır.
Bir geçiş dosya indirmez. Aynı görsel etki bir görsel dosyasıyla da elde edilebilirdi; geçiş, ek bir istek olmadan ve alan değiştiğinde yeniden ölçeklenerek üretir.
/* istasyon.css — 22. adım: geçişler */ .kunye { background-image: linear-gradient(to bottom, hsl(var(--ton) 61% 96%), hsl(var(--ton) 18% 97%)); } .olcum-grafigi { background-image: linear-gradient(to top, var(--cizgi) 0 1px, transparent 1px 100%); background-size: 100% 40px; } .yukleme-cubugu { background-image: linear-gradient( to right, var(--marka-koyu) 0 var(--oran, 0%), var(--cizgi) var(--oran, 0%) 100% ); }
.olcum-grafigi sınıfı ölçüm grafiğinin arkasına 40 birimde bir yatay ızgara çizgisi
koyar. Çizgiler belgede yoktur ve olmamalıdır: bir ızgara çizgisi bilgi taşımaz, okumaya
yardım eden bir görsel yardımcıdır.
.yukleme-cubugu özel bir özelliği durak konumu olarak kullanıyor. --oran değeri
değiştiğinde çubuğun dolu kısmı değişir; geçişin kendisi yeniden yazılmaz. Değerin belgeden
gelmesi durumunda dolgu oranının ayrıca erişilebilir biçimde — örneğin progress ögesiyle
ya da uygun ARIA öznitelikleriyle — bildirilmesi gerekir. Görsel çubuk tek başına bir
duruma karşılık gelmez.
Özet
- Geçiş bir renk değil bir arka plan görselidir;
background-imagedeğerine yazılır, doğal ölçüsü yoktur ve konulduğu alana göre boyutlanır. - Yazılmamış durak konumları doldurulur: ilk durak %0’a, son durak %100’e, aradakiler komşu bilinen noktalar arasına eşit aralıklarla dağıtılır.
- Durak konumlarını değiştirmek geçişin hızını değiştirir; iki durak aynı konuma yazıldığında karışacak mesafe kalmaz ve keskin bir kenar oluşur.
- Bir durağa iki konum yazmak o rengin aralık boyunca sabit kalmasını bildirir; çizgi ve şerit desenleri bu yazımla, dosya indirilmeden üretilir.
- Karışımın yapılacağı renk uzayı bildirilebilir; bildirilmediğinde sRGB kullanılır ve uzak renkler arasındaki ara tonlar soluklaşabilir.
Sonraki Adım
Kutuların içi ve arkası tamamlandı. Kenarları eksik: kenarlığın çizim biçimi, köşelerin yuvarlatılması ve kutunun dışına düşen gölgeler henüz ele alınmadı. Sonraki ders bu üç konuyu birleştirir ve köşe yarıçapının kenarlık kalınlığıyla nasıl hesaplandığını gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.