CSS Cascade Layers Gerçekte Ne Kazandırır?
CSS'de özgüllük çatışması büyüdükçe seçici gücünü artırmak çözüm olmaz. @layer sözdizimi, tasarım sistemi, utility ve bileşen stillerini kaynak sırasından bağımsız biçimde sıraya koyar; hangi stilin neden kazandığını koda yazar.
CSS'in özgüllük hesabı başta basit görünür. class seçici bir element seçiciden daha güçlüdür; id seçici ise her ikisini de geride bırakır. Sorun, bu sistemin tasarlandığı dönemde bir sayfanın tek bir ekip tarafından yazılan birkaç yüz satır CSS içerdiği gerçeğinde yatıyor. Günümüzde ise aynı bileşenin üzerinde bir tasarım sisteminin temel stilleri, bir utility kütüphanesinin sınıfları ve projeye özgü bileşen stilleri eş zamanlı çalışıyor.
Katmanlar devreye girdiğinde ilk soru genellikle şudur: sadece daha güçlü seçici yazsak olmaz mıydı? Çoğu durumda olurdu, ama bu yaklaşım borcu ertelemekten başka bir şey değildir. Bir gün başka biri daha güçlü seçici yazar, siz de !important eklersiniz; ardından o da !important ekler. Kaçınılmaz gün geldiğinde, hem !important hem yüksek özgüllük hem de rastgele kaynak sırası arasında istikrarsız bir CSS yığını kalır.
CSS Cascade Layers (@layer), bu sorunun köküne iner: stilleri özgüllükten bağımsız bir sıraya oturtur. Seçici ne kadar güçlü olursa olsun, katman sırası nihai kararı verir. Üç farklı CSS kaynağını aynı bileşen üzerinde yönetiyorsanız, katmanlar bu karmaşayı tanımlanabilir bir yapıya dönüştürür.
Özgüllük Çatışması Nasıl Büyür?
Özgüllük hesabı dört bölümlü bir değerdir: inline stiller, id seçiciler, class ve nitelik seçiciler, element seçiciler. Tarayıcı her seçici için bu değeri hesaplar ve kazananı belirler; kaynak sırası yalnızca özgüllükler eşitlendiğinde devreye girer.
Pratikte sorun şu şekilde ortaya çıkar: bir tasarım sistemi, düğme bileşenini .btn sınıfıyla tanımlar. Proje ekibi bu düğmeye bir varyant eklemek için .btn.btn--primary yazar; bu seçici özgüllük açısından daha güçlüdür. Bir utility kütüphanesi de .text-white gibi sınıflar içerir. Sonunda üçü aynı elementin üzerinde çakışır. Hangisinin kazandığı sorusu artık net değildir, çünkü cevap CSS dosyalarının yükleme sırasına bağlıdır ve bu sıra derleme konfigürasyonuyla değişebilir.
Gerçek tıkanma noktası seçici değil, bağlamdır. Özgüllük sistemi tek bir ekip tek bir kaynak için tasarlanmıştır; birden fazla kaynak katıldığında koordinasyon aracı yoktur. Katmanlar, bu koordinasyon aracını doğrudan dile ekler.
@layer Sözdizimi ve Katman Sırası
Temel sözdizimi iki parçadan oluşur: katman bildirimi ve katman tanımı.
@layer reset, base, components, utilities;
Bu satır katmanların sırasını belirler. Sonradan gelen katman tanımları bu sırayı değiştirmez; yalnızca ilgili katmana içerik ekler. Şu iki blok tamamen eşdeğerdir:
@layer reset, utilities;
@layer utilities {
.text-white { color: white; }
}
@layer reset {
* { box-sizing: border-box; }
}
Tarayıcı utilities katmanını son bildirilmiş olduğu için değil, sıra tanımında ikinci sıraya konduğu için daha güçlü kabul eder. reset katmanındaki bir kural, ne kadar güçlü seçiciyle yazılmış olursa olsun, utilities katmanındaki bir kurala yenik düşer; seçici özgüllüğü artık belirleyici değildir.
Sonuç önce gelir, neden sonra anlaşılır. Katman sırası bir kez tanımlandıktan sonra, hangi katmanın hangi dosyada ne zaman yüklendiği önem taşımaz; sıra sabittir. Bu, özgüllük savaşlarında kayıp olan şeydir: katman sisteminden önce CSS çıktısı derleme sırasına bağımlıydı ve bu sıra açıkça belgelenmemiş bir karardı.
Tasarım Sistemi, Utility ve Bileşen CSS'ini Yönetmek
Katmanların en somut faydası, farklı kaynaklardan gelen CSS'in nasıl birbirini ezeceğini açıkça ilan etmektir. Tipik bir proje için katman sırası şu şekilde düşünülebilir:
@layer reset, design-system, components, utilities;
Sıralamadaki mantık şudur: en az öncelikli olan en başa konur, en çok öncelikli olan en sona. reset her şeyin altında kalır. Tasarım sistemi temel stiller tanımlar; bileşenler bu temeli kullanarak spesifik yapılar kurar; utility sınıfları ise tek bir özelliği doğrudan uygular ve kazanması beklenir.
Mevcut bir projede Tailwind gibi bir araç zaten yüklüyse ve bir tasarım sistemi de varsa, katman bildirimi şu şekle gelebilir:
@layer reset, design-system, components, tailwind-base, tailwind-components, tailwind-utilities;
İki sistemin hangi durumda kazanacağını artık tek bir satırda okuyabilirsiniz. Bundan önce bu karar dolaylıydı; derleme sırası ve seçici özgüllüğüne gizlenmişti. Hangi katmanın hangi kaynağa karşılık geldiği açık olduğundan, yeni bir geliştirici sistemi anlamak için kaynak haritasını takip etmek zorunda kalmaz.
Bileşen düzeyinde iç içe katmanlar kullanılabilir:
@layer components {
@layer base, variants, states;
@layer base {
.btn { padding: 0.5rem 1rem; }
}
@layer variants {
.btn--primary { background: var(--color-primary); }
}
}
İç içe katmanlar, bir bileşen kütüphanesinin kendi içindeki öncelik sırasını dışarıya sızdırmadan yönetmesine olanak tanır. components katmanının dışından bakıldığında yalnızca tek bir katman görünür; içindeki hiyerarşi o katmanın özel alanıdır.
Katman Dışı Stiller ve Üçüncü Taraf CSS
Katman sistemi, katman dışında kalan stillere ayrı bir muamele yapar. Herhangi bir @layer bloğuna dahil edilmemiş bir stil, tüm katmanlardan daha güçlü kabul edilir. Bu davranış kasıtlıdır; mevcut projelere katman sistemi eklerken eski stillerin aniden düşük önceliğe düşmesini engeller.
@layer base {
.btn { color: blue; }
}
.btn { color: red; } /* katman dışında, kazanır */
Üçüncü taraf kütüphaneleri bu noktada ilginç bir sorun çıkarır. Eğer bir kütüphane katman sistemi tanımlamadan CSS yüklüyorsa, tüm stilleri katman dışı kabul edilir ve projedeki tüm katmanları ezerler. Çözüm, üçüncü taraf CSS'i bir katmana içe aktarmaktır:
@import url('third-party.css') layer(vendor);
Bu tek satır, kütüphanenin tüm stillerini vendor katmanına hapseder. Artık projenin katman sırası içinde kontrol edilebilir bir konuma gelir; kütüphane güncellendiğinde de katman dışına çıkamaz.
!important kuralları katman sisteminde tersine çalışır. Normal kurallarda son katman kazanırken, !important ile işaretlenmiş kurallar için ilk katman kazanır. reset katmanında !important kullanırsanız, en güçlü katmanda değil en güçsüz katmanda olduğunuzu sanarak tam tersini elde edersiniz; bu ters davranış, !important kullanımını katman sistemiyle birlikte neredeyse gereksiz kılar.
Ne Zaman Geri Teper?
Katman sistemi her projede fayda sağlamaz. Tek kişilik, birkaç yüz satır CSS içeren küçük projelerde ekstra bir @layer reset, components; bildirimi yalnızca karmaşıklık ekler. Seçici özgüllüğünü kafanızda rahatlıkla takip edebildiğiniz her proje, katman gerektirmeyen bir projedir.
Ekip içinde farkındalık eksikliği daha ciddi bir sorundur. Bir geliştirici katman tanımını atlar ve stillerini doğrudan katman dışında yazar; farkında olmadan tüm katman sistemini geçersiz kılar. Özgüllük savaşını gizlemek yerine tersine daha anlaşılmaz hale getirir, çünkü artık hem katman sırası hem katman dışı stiller hem de seçici özgüllüğü aynı anda devrededir.
Bir diğer tuzak, katman sırası tanımını birden fazla dosyaya yaymaktır. Hangi dosyanın önce yüklendiği sıraya karar vermeye başlarsa, orijinal özgüllük sorununu katman sırası sorununa çevirmiş olursunuz. Katman bildiriminin tek bir yerde, giriş dosyasında yapılması bu riski ortadan kaldırır.
Tarayıcı desteği 2023'ten bu yana tüm modern tarayıcılarda mevcuttur. Eski tarayıcıları desteklemeniz gerekiyorsa, katman sözdizimini tanımayan tarayıcılar için fallback planı yapmak şarttır; bu genellikle kritik stilleri katman dışında da tutmak anlamına gelir ve sistemin faydalarını kısmen azaltır.
Büyük Projelerde Katman Stratejisi
Ana katman bildiriminin projenin CSS giriş noktasında tek bir yerde yapılması ilk zorunlu karardır. Bu dosya proje boyunca değişmez; yalnızca yeni katman eklendiğinde güncellenir:
/* main.css */
@layer reset, tokens, base, design-system, components, utilities, overrides;
Katman adlandırma kuralı işlevsel olmalıdır. Kısa ama okunabilir isimler tercih edilmeli; hangi katmanın hangi CSS kaynağına karşılık geldiği net olmalıdır. u gibi kısaltmalar üç ay sonra ilk kez bakan bir geliştiriciye anlamsız gelir.
Bileşen kütüphaneleri veya paket olarak gelen tasarım sistemleri için @import ... layer() sözdiziminin sistematik kullanımı üçüncü zorunlu karardır. Dışarıdan gelen her CSS kaynağı bir katmana atanırsa, projenin kendi stilleri her zaman kazanır; harici kaynakların güncellenmesi beklenmedik kırılmalara neden olmaz. Yaygın bir senaryo şudur: bir UI bileşen kütüphanesi güncellenir ve bir sınıfın özgüllüğü değişir. Katman sistemi olmadan bu güncelleme görsel bozulmalara yol açabilir; katman sistemiyle, kütüphane kendi katmanında kaldığı sürece projenin stilleri etkilenmez.
Katman sistemini büyük bir projeye sonradan eklemek, sıfırdan kurmaktan daha dikkat ister. Mevcut stillerin katman dışı kalması onları en güçlü yapar; bu başlangıçta avantaj gibi görünse de, dosya dosya katmanlara taşımayı ertelediğiniz sürece sistemin faydaları gecikir. Kademeli geçişin en güvenli yolu, katman bildirimini önce ekleyip mevcut stilleri katman dışında bırakmak, ardından bileşen bazında katmanlara taşımaktır.
CSS'in özgüllük hesabı ortadan kalkmıyor; katman sistemi onu geçersiz kılmıyor. Aynı katman içindeki kurallar hâlâ özgüllüğe göre çözüme kavuşur. Değişen şey, farklı kaynakların aynı özellik için yarışmasıdır; bunu artık seçici karmaşıklığı değil, siz belirliyorsunuz.
Stillerin nereden geldiğini takip edemez hale geldiğinizde, seçici gücünü artırmak sorunu çözmez. Katmanların getirdiği yapı, neyin neden kazandığını koda yazar ve bu kodu okuyan herkes aynı sonuca ulaşır. Miras bırakan CSS'in en önemli niteliği öngörülebilirliktir; katman sistemi bu öngörüyü mimariye yerleştirir ve seçici özgüllüğünü yeniden bir araç haline getirir, bir engel değil.