CSS değişkenleriyle temalanabilir efekt yazmak
CSS özel değişkenleri (custom property), -- ile başlayan ve var() ile okunan gerçek CSS değerleridir. Sass değişkenlerinden temel farkı şudur: derleme anında değil çalışma anında çözülürler, kalıtım kurallarına uyarlar ve JavaScript'ten okunup yazılabilirler. Bir değişkeni değiştirdiğinde onu kullanan her bildirim anında güncellenir.
Efekt yazarken bu, tek bir kodun onlarca varyanta hizmet etmesi demektir. Rengi, süreyi, kalınlığı ve açıyı değişkene çıkarırsan aynı CSS'i kopyalayan kullanıcı yalnızca değişkenleri değiştirerek kendi temasına uydurur. Rehber tanımlama kurallarını, kalıtımı, yedek değerleri ve @property ile animasyonlanabilir değişkenleri anlatıyor.
Tanımlama, okuma ve yedek değer
Değişken normal bir bildirim gibi yazılır: --accent: #3b82f6. Adı büyük-küçük harfe duyarlıdır (--Accent ile --accent farklı değişkenlerdir) ve değer olarak neredeyse her şeyi kabul eder — renk, uzunluk, virgüllü liste, hatta yarım bir bildirim parçası. Tarayıcı değeri kullanıldığı yere kadar ayrıştırmaz; bu yüzden geçersiz bir değer yazmak tanım anında değil kullanım anında sorun çıkarır.
var() ikinci argüman olarak yedek değer alır: var(--accent, #3b82f6). Değişken hiç tanımlanmamışsa ya da değeri geçersizse yedek devreye girer. Yedeklerde virgül kullanılabilir; var(--gölge, 0 2px 6px rgb(0 0 0 / .3)) tamamen geçerlidir çünkü ilk virgülden sonrası bütünüyle yedek sayılır.
Tanımın nereye yazıldığı önemlidir. :root seçicisine yazılan değişken tüm belgeye yayılır; bir bileşenin kendi seçicisine yazılan ise yalnızca o eleman ve altındakiler için geçerlidir. Efektlerde ikinci yaklaşım tercih edilir: değişkenler bileşenin köküne yazılır, dışarıdan ezilebilir ama varsayılanları kendi içinde taşır.
.puls-buton {
/* Ayarlanabilir yüzey — dışarıdan ezilebilir, ama varsayılanı burada */
--renk: #3b82f6;
--sure: 1.6s;
--yayilma: 14px;
position: relative;
border-radius: 0.75rem;
background: var(--renk);
color: #fff;
padding: 0.7rem 1.3rem;
}
.puls-buton::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: 0 0 0 0 var(--renk);
animation: puls var(--sure) ease-out infinite;
}
@keyframes puls {
to { box-shadow: 0 0 0 var(--yayilma) transparent; }
}<button class="puls-buton">Varsayılan</button>
<button class="puls-buton" style="--renk: #0ea5e9">Açık mavi</button>
<button class="puls-buton" style="--renk: #1d4ed8; --sure: 2.4s">Yavaş</button>Kalıtım ve kapsam
Özel değişkenler normal CSS özellikleri gibi kalıtılır. Bir kaba tanımlanan değişkeni içindeki her eleman görür; aynı adı bir alt elemanda yeniden tanımlarsan yalnızca o alt ağaç yeni değeri kullanır. Bu, tema değiştirmenin en ucuz yoludur: bir sınıf ekleyerek tüm alt ağacın renklerini değiştirebilirsin.
Sözde sınıflar da bu mekanizmaya dahildir. :hover içinde bir değişkeni yeniden tanımlamak, o değişkeni kullanan tüm bildirimleri aynı anda günceller — beş ayrı :hover kuralı yazmak yerine tek bir değişken satırı yeter.
Kalıtımın bir sınırı var: değişken @keyframes bloğunun içinden okunduğunda, değeri animasyonun uygulandığı elemanda çözülür. Anahtar karede var(--x) yazıp --x değerini de aynı anda animasyonlamaya çalışmak beklendiği gibi çalışmaz; tarayıcı animasyon başlarken değeri bir kez çözer.
Duyarlı tasarımda değişkenleri medya sorgularıyla yeniden tanımlamak, aynı bildirimi iki kez yazmaktan çok daha temizdir. Kırılım noktasında yalnızca sayılar değişir, kuralların kendisi tek yerde durur.
.kart {
--yuzey: #121722;
--kenar: rgb(255 255 255 / 0.09);
--kalkis: 0px;
background: var(--yuzey);
border: 1px solid var(--kenar);
transform: translateY(var(--kalkis));
transition: transform 200ms ease, border-color 200ms ease;
}
/* Beş ayrı bildirim yerine iki değişken satırı */
.kart:hover {
--kenar: rgb(96 165 250 / 0.3);
--kalkis: -4px;
}
/* Alt ağaç teması: yalnızca bu kabın içi değişir */
.acik-tema .kart {
--yuzey: #f8fafc;
--kenar: rgb(15 23 42 / 0.12);
}
@media (max-width: 640px) {
.kart { --kalkis: 0px; } /* mobilde kalkış yok */
}@property: tipli ve animasyonlanabilir değişkenler
Normal bir özel değişken tarayıcı için sadece bir metin parçasıdır. --aci: 0deg ile --aci: 360deg arasında geçiş yazarsan hiçbir ara değer üretilmez; değer belirli bir anda sıçrar. Bunun sebebi tarayıcının değişkenin bir açı olduğunu bilmemesidir.
@property kuralı değişkene tip verir. syntax alanı değerin ne olduğunu (<angle>, <color>, <length>, <number>, <percentage>), inherits kalıtılıp kalıtılmayacağını, initial-value ise varsayılanı bildirir. Bu üç alan zorunludur; biri eksikse kural tamamen yok sayılır.
Tip bildirildikten sonra değişken gerçek bir animasyonlanabilir özellik gibi davranır. Gradyan açısını döndürmek, bir rengi yumuşakça değiştirmek ya da bir yüzdeyi animasyonlamak artık mümkündür. Bu, konik gradyanlı dönen çerçevelerin ve ilerleme halkalarının saf CSS ile yazılabilmesinin tek sebebidir.
Tip kontrolünün ikinci faydası doğrulamadır: <length> olarak bildirilmiş bir değişkene red yazmaya çalışırsan tarayıcı değeri reddeder ve initial-value'ya döner. Bu, geçersiz değerin efekti tamamen bozmasını engeller.
@property --aci {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
@property --vurgu {
syntax: "<color>";
inherits: true;
initial-value: #3b82f6;
}
.hale {
background: conic-gradient(from var(--aci), var(--vurgu), transparent 60%, var(--vurgu));
transition: --vurgu 400ms ease; /* renk geçişi artık çalışır */
animation: cevir 5s linear infinite;
}
.hale:hover { --vurgu: #0ea5e9; }
@keyframes cevir {
to { --aci: 360deg; } /* açı gerçekten ara değer üretir */
}Efektleri temalanabilir yazmak
İyi bir efekt, ayarlanabilir yüzeyini tek yerde toplar. Kural şu: kullanıcının değiştirmek isteyeceği her sayı ve renk bir değişken olmalı, geri kalan her şey sabit kalmalı. Tipik ayarlanabilir yüzey dört kalemden oluşur — vurgu rengi, animasyon süresi, boyut/kalınlık ve yoğunluk (opaklık, bulanıklık, yayılma).
Değişkenleri türetmek de mümkündür: --golge: 0 8px 24px rgb(from var(--renk) r g b / 0.35) yazmak, gölgeyi ana renkten otomatik üretir. rgb(from ...) göreli renk sözdizimi henüz her yerde yok, ama color-mix() daha geniş destekli bir alternatif sunar ve aynı işi yapar.
JavaScript tarafında değişkenler element.style.setProperty("--x", deger) ile yazılır ve getComputedStyle(el).getPropertyValue("--x") ile okunur. Fareyi takip eden ışık efektleri bu yolla yazılır: JavaScript yalnızca iki sayı günceller, geri kalan her şey CSS'te kalır. Sınıf değiştirmekten hem daha ucuz hem daha esnektir.
Son olarak yedek değerleri ihmal etme. Efekt kodunu kopyalayan biri değişken tanımlarını atlarsa, var(--renk, #3b82f6) yazımı efektin yine de çalışmasını sağlar. Sessizce bozulan bir efekt yerine varsayılanıyla çalışan bir efekt her zaman daha iyidir.
Ayrıntılı bir örnek için conic-gradient rehberindeki ilerleme halkasına bak: yüzde değeri tamamen bir CSS değişkeninden sürülüyor ve HTML tarafında tek bir style özniteliğiyle değiştiriliyor.
.isik-kart {
--renk: #3b82f6;
/* Gölge ve kenar ana renkten türetiliyor — tek değişken hepsini sürer */
--golge: 0 12px 30px color-mix(in srgb, var(--renk) 40%, transparent);
--kenar: color-mix(in srgb, var(--renk) 30%, transparent);
/* JavaScript yalnızca bu ikisini günceller */
--x: 50%;
--y: 50%;
position: relative;
border: 1px solid var(--kenar);
box-shadow: var(--golge);
background:
radial-gradient(240px circle at var(--x) var(--y),
color-mix(in srgb, var(--renk) 22%, transparent),
transparent 70%),
#0c1017;
}Katalogdan canlı örnekler
Aşağıdakiler --custom-property kullanan gerçek efektler — anlatılan teknik burada çalışır hâlde. Herhangi birine tıklayıp tam kaynağını açabilir, tarayıcı içi editörde değiştirip sonucu anında görebilirsin.
Tarayıcı desteği
Sürüm numaraları özelliğin öneksiz ve varsayılan olarak açık hâle geldiği ilk kararlı sürümü gösterir.
| Özellik | Tarayıcılar | Not |
|---|---|---|
| Özel değişkenler ve var() | Chrome 49+, Firefox 31+, Safari 9.1+, Edge 15+ | On yıla yakın süredir her yerde çalışıyor; polyfill gerekmez. |
| @property | Chrome 85+, Firefox 128+, Safari 16.4+ | Desteklenmediğinde kural yok sayılır ve değişken metin gibi davranır — animasyon çalışmaz ama statik görünüm bozulmaz. |
| color-mix() | Chrome 111+, Firefox 113+, Safari 16.2+ | Renk türetmenin geniş destekli yolu. Yedek olarak sabit bir renk yazmak eski tarayıcıları kurtarır. |
| Göreli renk sözdizimi rgb(from ...) | Chrome 119+, Safari 16.4+, Firefox 128+ | Bir renkten kanal okuyup yenisini üretir. Yeni olduğu için @supports ile korumak mantıklı. |
Yaygın hatalar
Değişken adını büyük-küçük harf farkıyla yazmak
--Accentile--accentiki ayrı değişkendir ve hata verilmez; efekt sessizce yedek değere düşer. Tek bir yazım kuralına bağlı kal.Değişkeni @property olmadan animasyonlamaya çalışmak
Tipsiz bir değişken tarayıcı için metindir ve ara değer üretilmez; geçiş süresi dolduğunda değer aniden sıçrar. Animasyon gerekiyorsa @property ile tip bildir.
Yedek değer yazmamak
Kodunu kopyalayan biri değişken tanımını atlarsa bildirim geçersiz olur ve efekt bozulur.
var(--renk, #3b82f6)yazımı bunu tek karakterle önler.:root'a bileşene özel değişken yazmak
Genel isim alanı hızla kirlenir ve iki efektin
--renkdeğişkeni çakışır. Bileşene özel değerleri bileşenin kendi seçicisine yaz, yalnızca gerçekten global olanları :root'a bırak.Değişkeni özellik adı olarak kullanmaya çalışmak
var(--ozellik): 10pxgeçersizdir; var() yalnızca değer tarafında çalışır. Değişkenle bir bildirimin tamamını üretmek de tarayıcılar arasında güvenilir değildir.
Sıkça sorulan sorular
- CSS değişkenleri Sass değişkenlerinin yerini alır mı?
- Farklı işler yaparlar. Sass değişkeni derleme anında çözülür ve çıktıda hiç görünmez; koşul ve döngü içinde kullanılabilir. CSS değişkeni çalışma anında yaşar, kalıtılır, medya sorgusuyla değişebilir ve JavaScript'ten güncellenebilir. Tema ve durum yönetimi için CSS değişkeni, derleme mantığı için Sass uygun.
- Değişkeni JavaScript'ten nasıl değiştiririm?
- element.style.setProperty("--renk", "#0ea5e9") ile yazarsın, getComputedStyle(element).getPropertyValue("--renk") ile okursun. Fare konumu, kaydırma ilerlemesi gibi sürekli değişen değerleri sınıf eklemek yerine değişkenle geçirmek çok daha ucuzdur.
- Değişken neden animasyonlanmıyor?
- Tarayıcı tipsiz bir özel değişkeni metin olarak görür ve iki metin arasında ara değer üretemez. @property ile syntax alanını bildirdiğinde (örneğin "<angle>" ya da "<color>") değişken gerçek bir animasyonlanabilir özellik hâline gelir.
- Değişkenleri :root'a mı yoksa bileşene mi yazmalıyım?
- Renk paleti ve tipografi ölçeği gibi gerçekten global değerler :root'a; bir efektin süresi, kalınlığı, yayılması gibi bileşene özel değerler o bileşenin kendi seçicisine yazılmalı. Böylece bileşen kendi varsayılanlarını taşır ve dışarıdan ezilmeye açık kalır.
- Değişken kullanmak performansı etkiler mi?
- Ölçülebilir bir maliyeti vardır ama pratikte ihmal edilebilir. Dikkat edilecek tek nokta, çok derin bir ağacın kökündeki bir değişkeni sık sık güncellemektir: değişiklik tüm alt ağaçta stil yeniden hesabı tetikler. Sık güncellenen değişkeni mümkün olduğunca hedefe yakın elemanda tut.
İlgili rehberler
- conic-gradient()conic-gradient ile halka, pasta ve parıltıRenkleri merkez etrafında döndürerek pasta grafik, ilerleme halkası ve dönen çerçeve parıltısı üretmek.
- @keyframes@keyframes ile CSS animasyonuAnahtar kare tanımlamaktan zamanlama fonksiyonlarına, gecikme zincirlerinden compositor performansına kadar CSS animasyonunun tamamı.
- :hover:hover ve geçişlerle etkileşim efektleriFare üstüne gelme durumunu yakalamak, geçişleri doğru özelliklerde yumuşatmak ve dokunmatik ekranda takılan hover sorununu çözmek.
- perspective / transformperspective ve 3D dönüşümlerDüzlemsel elemanları uzaya yerleştirmek: perspektif noktası, 3D bağlam, arka yüz görünürlüğü ve kart çevirme kalıbı.
Son güncelleme:
Tüm rehberler