DOM'nizin yalnızca sınırlı bir alt ağacında yer alan öğeleri seçmek için @scope'u nasıl kullanacağınızı öğrenin.
Hassas CSS seçici yazma sanatı
Seçicileri yazarken iki dünya arasında kaybolabilirsiniz. Bir yandan, hangi öğeleri seçeceğiniz konusunda oldukça spesifik olmak istersiniz. Diğer yandan, seçicilerinizin geçersiz kılınmasının kolay olmasını ve DOM yapısına sıkı sıkıya bağlı olmamasını istersiniz.
Örneğin, oldukça spesifik bir öğe seçimi olan "kart bileşeninin içerik alanındaki hero resim"i 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)
spesifikasyonu oldukça yüksek olduğundan kodunuz büyüdükçe geçersiz kılmayı zorlaştırır. - Doğrudan alt birleştiriciye dayalı olarak, 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. Çünkü bu, sayfanızdaki tüm resim öğelerinin seçilmesine neden olur.
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ştirdiler. Örneğin:
- BEM gibi metodolojiler, belirliliği düşük tutmak ve seçiminizde spesifik olmanıza izin vermek için bu öğeye
card__img card__img--hero
sınıfı vermenizi belirtir. - Kapsamlı CSS veya Stilli Bileşenler gibi JavaScript tabanlı çözümler, sayfanızın diğer tarafındaki öğeleri hedeflemelerini önlemek için seçicilerinize rastgele oluşturulmuş dizeler (ör.
sc-596d7e0e-4
) ekleyerek tüm seçicilerinizi yeniden yazar. - Bazı kitaplıklar, seçicileri tamamen kaldırır ve stil tetikleyicilerini doğrudan işaretlemenin içine yerleştirmenizi gerektirir.
Ama bunların hiçbirine ihtiyacınız yoksa ne yapabilirsiniz? CSS, yüksek belirginliğe sahip veya DOM'nize sıkı sıkıya bağlı seçiciler yazmanıza gerek kalmadan seçtiğiniz öğeler konusunda son derece spesifik olmanız için size bir yöntem sunsa ne olur? İşte burada @scope
devreye girer ve yalnızca DOM'nizin bir alt ağacında bulunan öğeleri seçmenize olanak tanır.
@scope ile tanışın
@scope
ile seçicilerinizin erişimini sınırlandırabilirsiniz. Bunu, hedeflemek istediğiniz alt ağacın üst sınırını belirleyen kapsam kökünü ayarlayarak yapabilirsiniz. Kapsam oluşturma kök kümesiyle, içerilen stil kuralları (kapsamlı stil kuralları adlı) yalnızca DOM'nin bu sınırlı alt ağacından seçim yapabilir.
Örneğin, .card
bileşeninde yalnızca <img>
öğelerini hedeflemek için .card
öğesini, @scope
kuralının kapsam kökü olarak ayarlarsınız.
@scope (.card) {
img {
border-color: green;
}
}
img { … }
kapsamlı stil kuralı yalnızca eşleşen .card
öğesinin kapsamındaki <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, @scope
kuralının alt sınırı belirleyen bir kapsam belirleme sınırını da kabul etmesidir.
@scope (.card) to (.card__content) {
img {
border-color: green;
}
}
Bu kapsamlı stil kuralı yalnızca üst öğe ağacında .card
ile .card__content
öğeleri arasına yerleştirilen <img>
öğelerini hedefler. Üst ve alt sınırları olan bu kapsam oluşturma türü, genellikle halka kapsamı olarak adlandırılır.
:scope
seçici
Varsayılan olarak, kapsama dahil olan tüm stil kuralları, kapsam köküne göre belirlenir. Kapsam oluşturma kök öğesinin kendisini hedeflemek de 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ının içindeki seçicilerin başına :scope
eklenir. İsterseniz :scope
ifadesini kendiniz belirleyerek açıkça belirtebilirsiniz. Alternatif olarak CSS Nesting'den &
seçiciyi de 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 oluşturma sınırı, kapsam köküyle belirli bir ilişki olmasını zorunlu kılmak 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 oluşturma sınırı, :scope
kullanılarak kapsam köklerinin 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 kendilerinin alt ağacın dışına çıkamayacağını unutmayın. Kapsama dahil olmayan öğeler seçilmeye çalışıldığından, :scope + p
gibi seçimler geçersizdir.
@scope
ve kesinlik
@scope
başlangıcında kullandığınız seçiciler, içerdiği seçicilerin kesinliğini etkilemez. Aşağıdaki örnekte, img
seçicinin kesinliği (0,0,1)
şeklindedir.
@scope (#sidebar) {
img { /* Specificity = (0,0,1) */
…
}
}
:scope
özelliğinin kesinliği, normal bir sanal sınıf olan (0,1,0)
değeridir.
@scope (#sidebar) {
:scope img { /* Specificity = (0,1,0) + (0,0,1) = (0,1,1) */
…
}
}
Aşağıdaki örnekte &
öğesi, kapsam kökü için kullanılan seçiciye dahili olarak, :is()
seçicisinin içine yerleştirilmiş şekilde yeniden yazılır. Sonunda, tarayıcı eşleşmeyi yapmak için seçici olarak :is(#sidebar, .card) img
kullanır. Bu işlem, artırma olarak bilinir.
@scope (#sidebar, .card) {
& img { /* desugars to `:is(#sidebar, .card) img` */
…
}
}
&
, :is()
kullanılarak sadeleştirildiğinden, &
öğesinin spesifikliği :is()
özgüllük kurallarına göre hesaplanır: &
işlevinin spesifikliği, en spesifik bağımsız değişkenidir.
Bu örneğe göre :is(#sidebar, .card)
, en belirgin bağımsız değişkeni olan #sidebar
ile ilgili olarak (1,0,0)
haline gelir. Bunu img
özelliğinin ((0,0,1)
) kesinliğiyle birleştirdiğinizde tüm karmaşık seçici için spesifik olarak (1,0,1)
elde edersiniz.
@scope (#sidebar, .card) {
& img { /* Specificity = (1,0,0) + (0,0,1) = (1,0,1) */
…
}
}
@scope
içinde :scope
ile &
arasındaki fark
Belirginliğin hesaplanma şekliyle ilgili farklılıkların yanı sıra, :scope
ile &
arasındaki başka bir fark da :scope
öğesinin eşleşen kapsam kökünü, &
ise kapsam kökünü eşleştirmek için kullanılan seçiciyi temsil etmesidir.
Bu nedenle, &
öğesini birden fazla kez kullanmak mümkündür. Bu, bir kapsam kökü içindeki kapsam kökünü eşleştiremeyeceğ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 */
…
}
}
Başlangıçsız kapsam
<style>
öğesiyle satır içi stiller yazarken, herhangi bir kapsam kökü belirtmeyerek stil kurallarının kapsamını <style>
öğesinin kapsayan üst öğesine ayarlayabilirsiniz. Bunu @scope
başlangıcını atlayarak yaparsı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, div
, <style>
öğesinin üst öğesi olduğundan, kapsamdaki kurallar yalnızca card__header
sınıf adına sahip div
içindeki öğeleri hedefler.
Bu şelalede @scope
@scope
, CSS Basamaklaması'nın içine yeni bir ölçüt daha ekler: yakınlık kapsamı. Adım, belirginlikten sonra, ancak görünüş sırasından önce gelir.
Farklı kapsam köklerine sahip stil kurallarında görünen bildirimler karşılaştırılırken, en az nesil veya eş öğe öğe içeren bildirim, kapsam kökü ile kapsamlı stil kuralı konusu arasında atlar.
Bu yeni adım, bir bileşenin çeşitli varyasyonlarını iç içe yerleştirirken yararlı olur. @scope
özelliğinin henüz kullanılmadığı ş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ını görüntülerken üçüncü bağlantı, .light
sınıfının uygulandığı bir div
alt öğesi olmasına rağmen black
yerine white
olur. Bunun nedeni, şelalenin kazananı belirlemek için kullandığı görünüm ölçütü sıralamasıdır. En son .dark a
açıklandığı için .light a
kuralından kazanacak
Kapsam oluşturma yakınlık ölçütü ile bu sorun artık çözülür:
@scope (.light) {
:scope { background: #ccc; }
a { color: black;}
}
@scope (.dark) {
:scope { background: #333; }
a { color: white; }
}
Kapsamdaki her iki a
seçici de aynı spesifikliğe sahip olduğundan kapsam belirleme yakınlık ölçütü devreye girer. Her iki seçiciyi de kapsam köklerine yakınlıklarına göre değerlendirir. Bu üçüncü a
öğesi için .light
kapsam kökü için yalnızca bir durak, .dark
bir duraklama ikidir. Bu nedenle, .light
konumundaki a
seçici kazanır.
Kapanış notu: Stil yalıtımı değil, seçici izolasyonu
Dikkat edilmesi gereken önemli bir nokta, @scope
özelliğinin seçicilerin erişimini sınırlandırdığı, stil izolasyonu sunmadığıdır. Devralınan alt mülklere ait mülkler, @scope
alt sınırından sonra da devralınmaya devam eder. Bu özelliklerden biri de color
özelliğidir. color
, donut kapsamı dahilinde olan bir öğe tanımlanırken halkanın deliğindeki çocuklara devralınmaya devam eder.
@scope (.card) to (.card__content) {
:scope {
color: hotpink;
}
}
Yukarıdaki örnekte, .card__content
öğesi ve alt öğeleri .card
değerini devraldıkları için hotpink
rengine sahiptir.
(rustam burkhanov'un Unsplash'teki kapak fotoğrafı)