Yayınlanma tarihi: 8 Ekim 2024
CSS iç içe yerleştirmeyle ilgili bazı garip tuhaflıkları düzeltmek için CSS Çalışma Grubu, CSSNestedDeclarations
arayüzünü CSS İç İçe Yerleştirme Spesifikasyonu'na eklemeye karar verdi. Bu eklemeyle birlikte, bazı iyileştirmelerin yanı sıra stil kurallarından sonra gelen bildirimler artık yukarı kaymıyor.
Bu değişiklikler, Chrome'un 130 sürümünden itibaren kullanılabilir ve Firefox Nightly 132 ile Safari Technology Preview 204'te test edilmeye hazırdır.
Tarayıcı desteği
CSSNestedDeclarations
olmadan CSS iç içe yerleştirme sorunu
CSS iç içe yerleştirmeyle ilgili dikkat edilmesi gereken noktalardan biri, aşağıdaki snippet'in başlangıçta beklediğiniz gibi çalışmamasıdır:
.foo {
width: fit-content;
@media screen {
background-color: red;
}
background-color: green;
}
Koda baktığınızda, background-color: green;
beyanı en son geldiği için <div class=foo>
öğesinin bir green
background-color
içerdiğini varsayabilirsiniz. Ancak bu durum, 130'dan önceki Chrome'da geçerli değildir. CSSNestedDeclarations
desteğinin bulunmadığı bu sürümlerde öğenin background-color
değeri red
olur.
130 kullanımdan önceki Chrome'un gerçek kuralı ayrıştırıldıktan sonra aşağıdaki gibidir:
.foo {
width: fit-content;
background-color: green;
@media screen {
& {
background-color: red;
}
}
}
Ayrıştırma işleminden sonra CSS'de iki değişiklik yapıldı:
background-color: green;
, diğer iki beyanla birleştirmek için kaydırıldı.- İç içe yerleştirilmiş
CSSMediaRule
,&
seçici kullanılarak beyanlarını ek birCSSStyleRule
içine sarmalamak için yeniden yazıldı.
Burada göreceğiniz diğer bir tipik değişiklik de ayrıştırıcının desteklemediği özellikleri atmasıdır.
CSSStyleRule
sayfasındaki cssText
bölümünü okuyarak "Ayrıştırdıktan sonra CSS"yi kendiniz inceleyebilirsiniz.
Bu etkileşimli oyun alanında kendiniz deneyin:
Bu CSS neden yeniden yazılıyor?
Bu dahili yeniden yazma işleminin neden gerçekleştiğini anlamak için bu CSSStyleRule
değerinin CSS Nesne Modeli'nde (CSSOM) nasıl temsil edildiğini anlamanız gerekir.
130'dan önceki Chrome'da, daha önce paylaşılan CSS snippet'i aşağıdaki şekilde serileştirilir:
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = ".foo"
.resolvedSelectorText = ".foo"
.specificity = "(0,1,0)"
.style (CSSStyleDeclaration, 2) =
- width: fit-content
- background-color: green
.cssRules (CSSRuleList, 1) =
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = "&"
.resolvedSelectorText = ":is(.foo)"
.specificity = "(0,1,0)"
.style (CSSStyleDeclaration, 1) =
- background-color: red
Bir CSSStyleRule
öğesinin sahip olduğu tüm özelliklerden aşağıdaki ikisi bu durumda alakalıdır:
- Tanımlamaları temsil eden bir
CSSStyleDeclaration
örneği olanstyle
mülkü. - Tüm iç içe yerleştirilmiş
CSSRule
nesnelerini içeren birCSSRuleList
olancssRules
özelliği.
CSS snippet'indeki tüm beyanlar CSStyleRule
öğesinin style
mülkünde sona erdiği için bilgi kaybı yaşanır. style
özelliğine baktığımızda, background-color: green
öğesinin iç içe yerleştirilmiş CSSMediaRule
öğesinden sonra tanımlandığı anlaşılmamaktadır.
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = ".foo"
.style (CSSStyleDeclaration, 2) =
- width: fit-content
- background-color: green
.cssRules (CSSRuleList, 1) =
↳ …
CSS motorunun düzgün çalışması için stil kuralının içeriğinin başında görünen özellikleri diğer kurallarla birlikte görünen özelliklerden ayırt edebilmesi gerekir. Bu nedenle, bu durum sorunlu bir durumdur.
CSSMediaRule
içindeki beyanlar aniden CSSStyleRule
içine yerleştiriliyor. Bunun nedeni, CSSMediaRule
öğesinin beyan içerecek şekilde tasarlanmamış olmasıdır.
CSSMediaRule
, cssRules
mülkü aracılığıyla erişilebilen iç içe yerleştirilmiş kurallar içerebileceğinden, bildirimler otomatik olarak bir CSSStyleRule
içine alınır.
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = "&"
.resolvedSelectorText = ":is(.foo)"
.specificity = "(0,1,0)"
.style (CSSStyleDeclaration, 1) =
- background-color: red
Bu sorunu nasıl çözebilirim?
CSS Çalışma Grubu, bu sorunu çözmek için çeşitli seçenekleri inceledi.
Önerilen çözümlerden biri, tüm salt bildirimleri iç içe yerleştirme seçicisiyle (&
) iç içe yerleştirilmiş bir CSSStyleRule
içine sarmalamaktı. Bu fikir, &
'un :is(…)
olarak ayrıştırılmasının aşağıdaki istenmeyen yan etkileri de dahil olmak üzere çeşitli nedenlerle reddedildi:
- Belirlilik üzerinde bir etkisi vardır. Bunun nedeni,
:is()
'ün en spesifik bağımsız değişkeninin özgünlüğünü devralmasıdır. - Orijinal dış seçicideki sözde öğelerle iyi çalışmaz. Bunun nedeni,
:is()
'ün seçici listesi bağımsız değişkeninde sözde öğeleri kabul etmemesidir.
Aşağıdaki örneği inceleyelim:
#foo, .foo, .foo::before {
width: fit-content;
background-color: red;
@media screen {
background-color: green;
}
}
Bu snippet ayrıştırıldıktan sonra, Chrome'da 130'dan önce şu hale gelir:
#foo,
.foo,
.foo::before {
width: fit-content;
background-color: red;
@media screen {
& {
background-color: green;
}
}
}
&
seçicisiyle iç içe yerleştirilmiş CSSRule
nedeniyle bu bir sorundur:
:is(#foo, .foo)
değerine kadar düzleştirilir ve bu sırada seçici listesinden.foo::before
atılır.(1,0,0)
özgünlüğü vardır ve bu, daha sonra üzerine yazılmasını zorlaştırır.
Kuralın neyi serileştirdiğini inceleyerek bunu kontrol edebilirsiniz:
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = "#foo, .foo, .foo::before"
.resolvedSelectorText = "#foo, .foo, .foo::before"
.specificity = (1,0,0),(0,1,0),(0,1,1)
.style (CSSStyleDeclaration, 2) =
- width: fit-content
- background-color: red
.cssRules (CSSRuleList, 1) =
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = "&"
.resolvedSelectorText = ":is(#foo, .foo, .foo::before)"
.specificity = (1,0,0)
.style (CSSStyleDeclaration, 1) =
- background-color: green
Görsel olarak da .foo::before
için background-color
değerinin green
yerine red
olduğu anlamına gelir.
CSS Çalışma Grubu'nun incelediği bir diğer yaklaşım, tüm iç içe yerleştirilmiş bildirimleri bir @nest
kuralına sarmalamaktı. Bu öneri, geliştirici deneyiminde gerileme yaratacağı için reddedildi.
CSSNestedDeclarations
arayüzü kullanıma sunuldu
CSS Çalışma Grubu, iç içe yerleştirilmiş bildirim kuralını uygulamaya karar verdi.
Bu iç içe yerleştirilmiş beyan kuralı, Chrome 130'dan itibaren Chrome'da uygulanmaktadır.
Tarayıcı desteği
İç içe yerleştirilmiş beyan kuralı, CSS ayrıştırıcısını doğrudan iç içe yerleştirilmiş art arda beyanları otomatik olarak bir CSSNestedDeclarations
örneğine sarmalayacak şekilde değiştirir. Bu CSSNestedDeclarations
örneği, serileştirildiğinde CSSStyleRule
öğesinin cssRules
mülkünde yer alır.
Örnek olarak aşağıdaki CSSStyleRule
tekrar ele alınır:
.foo {
width: fit-content;
@media screen {
background-color: red;
}
background-color: green;
}
Chrome 130 veya sonraki sürümlerde serileştirildiğinde aşağıdaki gibi görünür:
↳ CSSStyleRule
.type = STYLE_RULE
.selectorText = ".foo"
.resolvedSelectorText = ".foo"
.specificity = (0,1,0)
.style (CSSStyleDeclaration, 1) =
- width: fit-content
.cssRules (CSSRuleList, 2) =
↳ CSSMediaRule
.type = MEDIA_RULE
.cssRules (CSSRuleList, 1) =
↳ CSSNestedDeclarations
.style (CSSStyleDeclaration, 1) =
- background-color: red
↳ CSSNestedDeclarations
.style (CSSStyleDeclaration, 1) =
- background-color: green
CSSNestedDeclarations
kuralı CSSRuleList
içinde sona erdiğinden ayrıştırıcı, background-color: green
beyanının konumunu koruyabilir: background-color: red
beyanının (CSSMediaRule
'nin bir parçasıdır) sonrasında.
Ayrıca, bir CSSNestedDeclarations
örneğinin kullanılması, artık reddedilmiş olan diğer olası çözümlerin neden olduğu kötü yan etkilerden hiçbirini ortaya çıkarmaz: İç içe yerleştirilmiş beyanlar kuralı, aynı özgünlük davranışıyla üst stil kuralıyla tam olarak aynı öğeleri ve sözde öğeleri eşleştirir.
Bunun kanıtı, CSSStyleRule
'un cssText
değerini geri okumaktır. İç içe yerleştirilmiş bildirimler kuralı sayesinde, giriş CSS'siyle aynıdır:
.foo {
width: fit-content;
@media screen {
background-color: red;
}
background-color: green;
}
Bunun sizin için anlamı:
Bu, CSS iç içe yerleştirme özelliğinin Chrome 130'dan itibaren çok daha iyi hale geldiği anlamına gelir. Ancak, salt beyanları iç içe yerleştirilmiş kurallarla iç içe yerleştiriyorsanız kodunuzun bir kısmını gözden geçirmeniz gerekebilir.
@starting-style
özelliğinin kullanıldığı aşağıdaki örneği ele alalım
/* This does not work in Chrome 130 */
#mypopover:popover-open {
@starting-style {
opacity: 0;
scale: 0.5;
}
opacity: 1;
scale: 1;
}
Chrome 130'tan önce bu bildirimler kaldırılırdı. opacity: 1;
ve scale: 1;
beyanları CSSStyleRule.style
'ye, ardından CSSStyleRule.cssRules
'te bir CSSStartingStyleRule
(@starting-style
kuralını temsil eder) eklenir.
Chrome 130'dan itibaren, bildirimler artık kaldırılmaz ve CSSStyleRule.cssRules
içinde iki iç içe yerleştirilmiş CSSRule
nesnesi elde edersiniz. Sırasıyla: bir CSSStartingStyleRule
(@starting-style
kuralını temsil eder) ve opacity: 1; scale: 1;
beyanlarını içeren bir CSSNestedDeclarations
.
Bu davranış değişikliği nedeniyle, @starting-style
beyanlarının üzerine CSSNestedDeclarations
örneğinde bulunanlar yazılır ve giriş animasyonu kaldırılır.
Kodu düzeltmek için @starting-style
bloğunun normal bildirimlerin ardından geldiğinden emin olun. Örneğin:
/* This works in Chrome 130 */
#mypopover:popover-open {
opacity: 1;
scale: 1;
@starting-style {
opacity: 0;
scale: 0.5;
}
}
CSS iç içe yerleştirme özelliğini kullanırken iç içe yerleştirilmiş beyanlarınızı iç içe yerleştirilmiş kuralların üzerinde tutarsanız kodunuz, CSS iç içe yerleştirmeyi destekleyen tüm tarayıcıların çoğunda sorunsuz çalışır.
Son olarak, CSSNestedDeclarations
özelliğinin kullanılabilir olup olmadığını tespit etmek istiyorsanız aşağıdaki JavaScript snippet'ini kullanabilirsiniz:
if (!("CSSNestedDeclarations" in self && "style" in CSSNestedDeclarations.prototype)) {
// CSSNestedDeclarations is not available
}