Yalnızca DOM'unuzun sınırlı bir alt ağacındaki öğeleri seçmek için @scope'u nasıl kullanacağınızı öğrenin.
CSS seçicileri yazmanın hassas sanatı
Seçici yazarken iki dünya arasında kararsız kalabilirsiniz. Bir yandan, hangi öğeleri seçeceğiniz konusunda oldukça net olmanız gerekir. Öte yandan, seçicilerinizin geçersiz kılınmasının kolay olmasını ve DOM yapısına sıkı bir şekilde bağlı olmamasını istersiniz.
Örneğin, "kart bileşeninin içerik alanındaki hero resmini" (oldukça spesifik bir öğe seçimidir) seçmek istediğinizde büyük olasılıkla .card > .content > img.hero
gibi bir seçici yazmak istemezsiniz.
- Bu seçicinin
(0,3,1)
değerine sahip oldukça yüksek bir özelliği vardır. Bu durum, kodunuz büyüdükçe istisnayı zorlaştırır. - Doğrudan alt öğe birleştiriciyi kullanarak DOM yapısına sıkı bir şekilde bağlanır. İşaretleme değişirse CSS'nizi de değiştirmeniz gerekir.
Ancak bu öğenin seçicisi olarak yalnızca img
yazmak da istemezsiniz. Aksi takdirde sayfanızdaki tüm resim öğeleri seçilir.
Bu konuda doğru dengeyi bulmak genellikle oldukça zordur. Yıllar içinde bazı geliştiriciler, bu gibi durumlarda size yardımcı olacak çözümler ve geçici çözümler geliştirdi. Örneğin:
- BEM gibi metodolojiler, seçtiğiniz öğelerde ayrıntılı olmaya izin verirken belirginliği düşük tutmak için bu öğeye
card__img card__img--hero
sınıfı vermenizi zorunlu kılar. - Kapsamlı CSS veya Stillendirilmiş Bileşenler gibi JavaScript tabanlı çözümler, sayfanızın diğer tarafındaki öğeleri hedeflemelerini önlemek için seçicilerinize rastgele oluşturulmuş dize (ör.
sc-596d7e0e-4
) ekleyerek tüm seçicilerinizi yeniden yazar. - Bazı kitaplıklarda seçiciler tamamen kaldırılır ve stil tetikleyicilerini doğrudan işaretlemeye yerleştirmeniz istenir.
Peki bunların hiçbirine ihtiyacınız yoksa ne olur? CSS, yüksek özgünlükte veya DOM'unuza sıkı sıkıya bağlı seçiciler yazmanıza gerek kalmadan hangi öğeleri seçeceğiniz konusunda oldukça spesifik olmanızı sağlayacak bir yöntem sunsa ne olurdu? İşte bu noktada @scope
devreye girer. @scope
, yalnızca DOM'unuzun bir alt ağacındaki öğeleri seçmenize olanak tanır.
@scope ile tanışın
@scope
ile seçicilerinizin erişimini sınırlayabilirsiniz. Bunu, hedeflemek istediğiniz alt ağacın üst sınırını belirleyen kapsama kökünü ayarlayarak yaparsınız. Kapsam kökü ayarlandığında, kapsamlı stil kuralları olarak adlandırılan kapsayıcı stil kuralları yalnızca DOM'un bu sınırlı alt ağacından seçim yapabilir.
Örneğin, yalnızca .card
bileşenindeki <img>
öğelerini hedeflemek için .card
bileşenini @scope
at-kuralının kapsam kökü olarak ayarlayın.
@scope (.card) {
img {
border-color: green;
}
}
Kapsamlı stil kuralı img { … }
, yalnızca eşleşen .card
öğesinin kapsamında olan <img>
öğelerini etkili bir şekilde seçebilir.
Kartın içerik alanındaki (.card__content
) <img>
öğelerinin seçilmesini önlemek için img
seçiciyi daha spesifik hale getirebilirsiniz. Bunu yapmanın bir diğer yolu da @scope
at-kuralı'nın alt sınırı belirleyen bir kapsama sınırı da kabul ettiği gerçeğini kullanmaktır.
@scope (.card) to (.card__content) {
img {
border-color: green;
}
}
Bu kapsamlı stil kuralı yalnızca üst öğe ağacında .card
ve .card__content
öğeleri arasına yerleştirilen <img>
öğelerini hedefler. Üst ve alt sınırı olan bu kapsam türüne genellikle halka kapsam denir.
:scope
seçici
Varsayılan olarak, tüm kapsamlı stil kuralları kapsamlandırma köküne göredir. Kapsamlandırma kök öğesinin kendisini de hedeflemek mümkündür. Bunun için :scope
seçiciyi kullanın.
@scope (.card) {
:scope {
/* Selects the matched .card itself */
}
img {
/* Selects img elements that are a child of .card */
}
}
Kapsamlı stil kuralları içindeki seçicilere :scope
ön ek olarak eklenir. İsterseniz :scope
ön ekini ekleyerek bu konuda açıkça belirtebilirsiniz. Alternatif olarak, CSS İç İçe Yerleştirme'den &
seçicisini ekleyebilirsiniz.
@scope (.card) {
img {
/* Selects img elements that are a child of .card */
}
:scope img {
/* Also selects img elements that are a child of .card */
}
& img {
/* Also selects img elements that are a child of .card */
}
}
Kapsam sınırı, kapsam köküyle belirli bir ilişki gerektirmek için :scope
sözde sınıfını kullanabilir:
/* .content is only a limit when it is a direct child of the :scope */
@scope (.media-object) to (:scope > .content) { ... }
Kapsam sınırı, :scope
kullanarak kapsam kökünün dışındaki öğelere de referans verebilir. Örneğin:
/* .content is only a limit when the :scope is inside .sidebar */
@scope (.media-object) to (.sidebar :scope .content) { ... }
Kapsamlı stil kurallarının alt ağaçtan kaçamayacağını unutmayın. Kapsam dışındaki öğeleri seçmeye çalıştığı için :scope + p
gibi seçimler geçersizdir.
@scope
ve belirlilik
@scope
için giriş bölümünde kullandığınız seçiciler, kapsanan seçicilerin özgünlüğünü etkilemez. Aşağıdaki örnekte, img
seçicisinin özgünlüğü hâlâ (0,0,1)
'dur.
@scope (#sidebar) {
img { /* Specificity = (0,0,1) */
…
}
}
:scope
, normal bir sözde sınıf olan (0,1,0)
ile aynı özgünlüğe sahiptir.
@scope (#sidebar) {
:scope img { /* Specificity = (0,1,0) + (0,0,1) = (0,1,1) */
…
}
}
Aşağıdaki örnekte, &
dahili olarak bir :is()
seçicisinin içine sarmalanarak kapsamlandırma kökü için kullanılan seçiciye yeniden yazılır. Sonuç olarak tarayıcı, eşleştirmeyi yapmak için seçici olarak :is(#sidebar, .card) img
değerini kullanır. Bu işleme şeker azaltma denir.
@scope (#sidebar, .card) {
& img { /* desugars to `:is(#sidebar, .card) img` */
…
}
}
&
, :is()
kullanılarak şekerden arındırıldığı için &
'ün özgünlüğü :is()
özgünlük kurallarına göre hesaplanır: &
'ün özgünlüğü, en ayrıntılı bağımsız değişkeninin özgünlüğüdür.
Bu örnekte, :is(#sidebar, .card)
'ün özgünlüğü en spesifik bağımsız değişkeninin (#sidebar
) özgünlüğüdür ve bu nedenle (1,0,0)
olur. Bunu img
'ün özgünlüğüyle ((0,0,1)
) birleştirdiğinizde karmaşık seçicinin tamamının özgünlüğü olarak (1,0,1)
elde edersiniz.
@scope (#sidebar, .card) {
& img { /* Specificity = (1,0,0) + (0,0,1) = (1,0,1) */
…
}
}
@scope
içindeki :scope
ile &
arasındaki fark
Belirliliğin hesaplanmasıyla ilgili farklılıkların yanı sıra :scope
ile &
arasındaki bir diğer fark da :scope
'ün eşleşen kapsamlandırma kökünü temsil etmesi, &
'un ise kapsamlandırma kökünü eşleştirmek için kullanılan seçiciyi temsil etmesidir.
Bu nedenle, &
öğesini birden fazla kez kullanabilirsiniz. Bu, kapsamlandırma kökünü bir kapsamlandırma kökünün içinde eşleştiremediğiniz için yalnızca bir kez kullanabileceğiniz :scope
ile zıttır.
@scope (.card) {
& & { /* Selects a `.card` in the matched root .card */
}
:scope :scope { /* ❌ Does not work */
…
}
}
Girişsiz kapsam
<style>
öğesiyle satır içi stiller yazarken herhangi bir kapsamlandırma kökü belirtmeden stil kurallarını <style>
öğesinin kapsayıcı üst öğesine göre belirleyebilirsiniz. Bunu yapmak için @scope
'ün girişini atlarsınız.
<div class="card">
<div class="card__header">
<style>
@scope {
img {
border-color: green;
}
}
</style>
<h1>Card Title</h1>
<img src="…" height="32" class="hero">
</div>
<div class="card__content">
<p><img src="…" height="32"></p>
</div>
</div>
Yukarıdaki örnekte, kapsamlı kurallar yalnızca div
öğesinin içinde bulunan ve sınıf adı card__header
olan öğeleri hedefler. Bunun nedeni, div
öğesinin <style>
öğesinin üst öğesi olmasıdır.
Şelalede @scope
@scope
, CSS basamaklı düzeni içinde yeni bir ölçüt de ekler: kapsama yakınlığı. Bu adım, özgünlükten sonra ancak görünme sırasından önce gelir.
Farklı kapsam köklerine sahip stil kurallarında görünen beyanlar karşılaştırılırken, kapsam kökü ile kapsamlı stil kuralı öznesi arasında en az nesil veya kardeş öğe atlaması olan beyan kazanır.
Bu yeni adım, bir bileşenin çeşitli varyantlarını iç içe yerleştirirken kullanışlıdır. Henüz @scope
kullanmayan şu örneği ele alalım:
<style>
.light { background: #ccc; }
.dark { background: #333; }
.light a { color: black; }
.dark a { color: white; }
</style>
<div class="light">
<p><a href="#">What color am I?</a></p>
<div class="dark">
<p><a href="#">What about me?</a></p>
<div class="light">
<p><a href="#">Am I the same as the first?</a></p>
</div>
</div>
</div>
Bu küçük işaretleme parçası görüntülenirken, üçüncü bağlantı .light
sınıfı uygulanmış bir div
öğesinin alt öğesi olmasına rağmen black
yerine white
olur. Bunun nedeni, kazananı belirlemek için basamaklı listelerin burada kullandığı görünme sırası ölçütüdür. .dark a
'ün en son ilan edildiğini görür ve .light a
kuralı uyarınca kazanır
Kapsam yakınlığı ölçütüyle bu sorun artık çözüldü:
@scope (.light) {
:scope { background: #ccc; }
a { color: black;}
}
@scope (.dark) {
:scope { background: #333; }
a { color: white; }
}
Her iki kapsamlı a
seçici de aynı özgünlüğe sahip olduğundan kapsama yakınlığı ölçütü devreye girer. Her iki seçiciyi de kapsam köklerine olan yakınlıklarına göre ağırlıklandırır. Üçüncü a
öğesi için .light
kapsama köküne yalnızca bir sıçrama, .dark
köküne ise iki sıçrama yapılır. Bu nedenle, .light
içindeki a
seçici kazanır.
Kapanış notu: Stil izolasyonu değil, seçici izolasyonu
@scope
'ün seçicilere erişimi sınırladığı, stil izolasyonu sunmadığı önemli bir noktadır. Alt öğelere devralınan özellikler, @scope
alt sınırının ötesinde devralmaya devam eder. Bu tür özelliklerden biri color
özelliğidir. Birini donut kapsamının içinde beyan ederken color
, donutun deliğinin içindeki alt öğelere de devralınır.
@scope (.card) to (.card__content) {
:scope {
color: hotpink;
}
}
Yukarıdaki örnekte, .card__content
öğesi ve alt öğeleri, .card
öğesinden değer devraldığı için hotpink
rengi kullanır.
(Kapak fotoğrafı: Rustam Burkhanov, Unsplash)