Kapsayıcı sorguları, alt öğelerine stil uygulamak için üst öğenin özelliklerini (ör. genişliği veya yüksekliği) hedefleyen stil mantığı yazmanıza olanak tanıyan yeni bir CSS özelliğidir. Kısa süre önce, tarayıcılarda desteğin kullanıma sunulmasıyla aynı zamanda polyfill için büyük bir güncelleme yayınlandı.
Bu yayında, polyfill'in nasıl çalıştığına, üstesinden geldiği zorluklara ve ziyaretçilerinize mükemmel bir kullanıcı deneyimi sunmak için kullanırken dikkat etmeniz gereken en iyi uygulamalara göz atabilirsiniz.
Perde arkası
Transpilasyon
Bir tarayıcıdaki CSS ayrıştırıcısı, yeni @container
kuralı gibi bilinmeyen bir at-kuralıyla karşılaştığında bu kuralı hiç yokmuş gibi atar. Bu nedenle, polyfill'in yapması gereken ilk ve en önemli şey, bir @container
sorgusunu atılmayacağı bir şeye dönüştürmektir.
Derlemenin ilk adımı, üst düzey @container
kuralını bir @media sorgusuna dönüştürmektir. Bu sayede, içerikler genellikle gruplandırılmış halde kalır. Örneğin, CSSOM API'leri kullanılırken ve CSS kaynağı görüntülenirken.
@container (width > 300px) { /* content */ }
@media all { /* content */ }
Kapsayıcı sorguları kullanılmadan önce, CSS'de yazarların kural gruplarını keyfi olarak etkinleştirmesi veya devre dışı bırakması için bir yöntem yoktu. Bu davranışı polyfill yapmak için kapsayıcı sorgusunun içindeki kuralların da dönüştürülmesi gerekir. Her @container
'ye kendi benzersiz kimliği (ör. 123
) verilir. Bu kimlik, her seçiciyi yalnızca öğede bu kimliği içeren bir cq-XYZ
özelliği olduğunda geçerli olacak şekilde dönüştürmek için kullanılır. Bu özellik, çalışma zamanında polyfill tarafından ayarlanır.
@container (width > 300px) { .card { /* ... */ } }
@media all { .card:where([cq-XYZ~="123"]) { /* ... */ } }
:where(...)
sözde sınıfının kullanıldığına dikkat edin. Normalde ek bir özellik seçici eklemek, seçicinin özellik değerini artırır. Sanal sınıf sayesinde, orijinal özgüllüğü korunurken ek koşul uygulanabilir. Bunun neden önemli olduğunu anlamak için aşağıdaki örneği inceleyin:
@container (width > 300px) {
.card {
color: blue;
}
}
.card {
color: red;
}
Bu CSS'de, .card
sınıfına sahip bir öğe her zaman color: red
özelliğine sahip olmalıdır. Çünkü sonraki kural, aynı seçici ve özgünlükle önceki kuralı her zaman geçersiz kılar. Bu nedenle, ilk kuralı derleyip :where(...)
olmadan ek bir özellik seçici eklemek özgüllüğü artıracak ve color: blue
'ın hatalı bir şekilde uygulanmasına neden olacaktır.
Ancak :where(...)
sözde sınıfı oldukça yeni. Bu özelliği desteklemeyen tarayıcılar için polyfill güvenli ve kolay bir geçici çözüm sunar: @container
kurallarınıza manuel olarak bir :not(.container-query-polyfill)
seçici ekleyerek kurallarınızın özgünlüğünü kasıtlı olarak artırabilirsiniz:
@container (width > 300px) { .card { color: blue; } } .card { color: red; }
@container (width > 300px) { .card:not(.container-query-polyfill) { color: blue; } } .card { color: red; }
Bu işlemin bazı avantajları vardır:
- Kaynak CSS'deki seçici değiştiğinden, özgünlükteki fark açıkça görülebilir. Bu, geçici çözümü veya polyfill'i desteklemeniz gerekmediğinde etkilenen öğeleri bilmeniz için doküman görevi de görür.
- polyfill bunu değiştirmediğinden, kuralların özgünlüğü her zaman aynı olur.
Doldurma, transpilasyon sırasında bu sözde öğeyi aynı özgünlükteki özellik seçiciyle değiştirir. Herhangi bir sürprizle karşılaşmamak için çoklu dolgu, her iki seçiciyi de kullanır: Öğenin çoklu dolgu özelliğini alıp almayacağını belirlemek için orijinal kaynak seçici, stil oluşturmak için ise dönüştürülmüş seçici kullanılır.
Sözde öğeler
Şu soruyu sorabilirsiniz: Polifill, bir öğede cq-XYZ
özelliğini 123
benzersiz kapsayıcı kimliğini içerecek şekilde ayarlarsa, özellikleri ayarlanamayan sözde öğeler nasıl desteklenir?
Sanal öğeler her zaman DOM'daki kaynak öğe olarak adlandırılan gerçek bir öğeye bağlıdır. Koşullu seçici, derleme sırasında bunun yerine bu gerçek öğeye uygulanır:
@container (width > 300px) { #foo::before { /* ... */ } }
@media all { #foo:where([cq-XYZ~="123"])::before { /* ... */ } }
Koşullu seçici, #foo::before:where([cq-XYZ~="123"])
olarak dönüştürülmek yerine (geçersiz olur) kaynak öğenin (#foo
) sonuna taşınır.
Ancak bunun için gereken tek şey bu değildir. Bir kapsayıcının içinde bulunmayan hiçbir şeyi değiştirmesine izin verilmez (ve kapsayıcı kendi içinde olamaz). Ancak #foo
, sorgulanan kapsayıcı öğesi olsaydı tam olarak bunun olacağını düşünün. #foo[cq-XYZ]
özelliği yanlışlıkla değiştirilir ve tüm #foo
kuralları yanlışlıkla uygulanır.
Bu sorunu düzeltmek için polyfill aslında iki özellik kullanır: Biri yalnızca bir öğeye üst öğe tarafından uygulanabilir, diğeri ise öğenin kendisine uygulayabileceği bir özelliktir. İkinci özellik, sözde öğeleri hedefleyen seçiciler için kullanılır.
@container (width > 300px) { #foo, #foo::before { /* ... */ } }
@media all { #foo:where([cq-XYZ-A~="123"]), #foo:where([cq-XYZ-B~="123"])::before { /* ... */ } }
Bir kapsayıcı, ilk özelliği (cq-XYZ-A
) hiçbir zaman kendisine uygulamaz. Bu nedenle, ilk seçici yalnızca farklı bir üst kapsayıcı kapsayıcı koşullarını karşılayıp uygularsa eşleşir.
Kapsayıcıya göreceli birimler
Kapsayıcı sorguları, CSS'nizde kullanabileceğiniz birkaç yeni birim de içerir. Örneğin, en yakın uygun üst kapsayıcının genişliğinin ve yüksekliğinin (sırasıyla) %1'i için cqw
ve cqh
gibi birimler kullanılabilir. Bu özellikleri desteklemek için birim, CSS Özel Özellikleri kullanılarak bir calc(...)
ifadesine dönüştürülür. Polifill, kapsayıcı öğesindeki satır içi stiller aracılığıyla bu özelliklerin değerlerini ayarlar.
.card { width: 10cqw; height: 10cqh; }
.card { width: calc(10 * --cq-XYZ-cqw); height: calc(10 * --cq-XYZ-cqh); }
Satır içi boyut ve blok boyutu için sırasıyla cqi
ve cqb
gibi mantıksal birimler de vardır. Satır içi ve blok eksenleri, sorgulanan öğenin değil, birimi kullanan öğenin writing-mode
özelliğine göre belirlendiği için bu yöntemler biraz daha karmaşıktır. Bu özelliği desteklemek için polyfill, writing-mode
değeri üst öğesinden farklı olan tüm öğelere satır içi stil uygular.
/* Element with a horizontal writing mode */
--cq-XYZ-cqi: var(--cq-XYZ-cqw);
--cq-XYZ-cqb: var(--cq-XYZ-cqh);
/* Element with a vertical writing mode */
--cq-XYZ-cqi: var(--cq-XYZ-cqh);
--cq-XYZ-cqb: var(--cq-XYZ-cqw);
Artık birimler, önceki gibi uygun CSS özel mülküne dönüştürülebilir.
Özellikler
Kapsayıcı sorguları, container-type
ve container-name
gibi birkaç yeni CSS özelliği de ekler. getComputedStyle(...)
gibi API'ler bilinmeyen veya geçersiz özelliklerle kullanılamayacağından bunlar da ayrıştırıldıktan sonra CSS özel özelliklerine dönüştürülür. Bir özellik ayrıştırılamazsa (örneğin, geçersiz veya bilinmeyen bir değer içeriyorsa) tarayıcı tarafından işlenmesi için olduğu gibi bırakılır.
.card { container-name: card-container; container-type: inline-size; }
.card { --cq-XYZ-container-name: card-container; --cq-XYZ-container-type: inline-size; }
Bu özellikler keşfedildiklerinde dönüştürülür. Bu sayede polyfill, @supports
gibi diğer CSS özellikleriyle sorunsuz bir şekilde çalışır. Bu işlev, aşağıda açıklandığı gibi polyfill'i kullanmayla ilgili en iyi uygulamaların temelini oluşturur.
@supports (container-type: inline-size) { /* ... */ }
@supports (--cq-XYZ-container-type: inline-size) { /* ... */ }
CSS özel özellikleri varsayılan olarak devralınır. Örneğin, .card
öğesinin tüm alt öğeleri --cq-XYZ-container-name
ve --cq-XYZ-container-type
değerini alır. Yerel mülkler kesinlikle bu şekilde davranmaz. Bu sorunu çözmek için polyfill, kullanıcı stillerinden önce aşağıdaki kuralı ekler. Böylece, başka bir kural tarafından kasıtlı olarak geçersiz kılınmadığı sürece her öğenin ilk değerleri almasını sağlar.
* {
--cq-XYZ-container-name: none;
--cq-XYZ-container-type: normal;
}
En iyi uygulamalar
Çoğu ziyaretçinin, yerleşik kapsayıcı sorgu desteğine sahip tarayıcılar kullanması beklense de geri kalan ziyaretçilerinize iyi bir deneyim sunmak yine de önemlidir.
İlk yükleme sırasında, polyfill'in sayfayı düzenleyebilmesi için birçok şeyin gerçekleşmesi gerekir:
- Polifill'in yüklenmesi ve başlatılması gerekir.
- Stil sayfalarının ayrıştırılması ve derlenmesi gerekir. Harici stil sayfasının ham kaynağına erişmek için herhangi bir API olmadığından, ideal olarak yalnızca tarayıcı önbelleğinden olsa da harici stil sayfasının eşzamansız olarak yeniden getirilmesi gerekebilir.
Bu endişeler polyfill tarafından dikkatlice ele alınmazsa Core Web Vitals metriğiniz geriye gidebilir.
Ziyaretçilerinize keyifli bir deneyim sunmanızı kolaylaştırmak için polyfill, Largest Contentful Paint (LCP) pahasına olsa bile First Input Delay (FID) ve Cumulative Layout Shift (CLS)'e öncelik verecek şekilde tasarlanmıştır. Daha açık belirtmek gerekirse, polyfill, kapsayıcı sorgularınızın ilk boyamadan önce değerlendirileceği konusunda garanti vermez. Bu, en iyi kullanıcı deneyimi için, kapsayıcı sorgularının kullanılmasından boyutu veya konumu etkilenecek tüm içeriklerin, polyfill yüklenip CSS'nizi transpile edene kadar gizlendiğinden emin olmanız gerekir. Bunu yapmanın bir yolu, @supports
kuralı kullanmaktır:
@supports not (container-type: inline-size) {
#content {
visibility: hidden;
}
}
Ziyaretçiye bir şeyler olduğunu bildirmek için bunu, (gizli) içeriğinizin üzerine kesinlikle yerleştirilmiş, saf CSS yükleme animasyonunu kullanarak birleştirmeniz önerilir. Bu yaklaşımın tam demosunu burada bulabilirsiniz.
Bu yaklaşımın birkaç nedeni vardır:
- Saf CSS yükleyici, yeni tarayıcılara sahip kullanıcılar için yükü en aza indirirken eski tarayıcılarda ve daha yavaş ağlarda olanlara hafif geri bildirim sağlar.
- Yükleyicinin mutlak konumunu
visibility: hidden
ile birleştirerek düzen kaymasından kaçınabilirsiniz. - Polifill yüklendikten sonra bu
@supports
koşulu artık geçerli olmaz ve içeriğiniz gösterilir. - Kapsayıcı sorguları için yerleşik destek sunan tarayıcılarda bu koşul hiçbir zaman geçerli olmaz ve sayfa, ilk boyamada beklendiği gibi gösterilir.
Sonuç
Eski tarayıcılarda kapsayıcı sorgularını kullanmak istiyorsanız polyfill'i deneyin. Herhangi bir sorunla karşılaşırsanız sorun kaydı oluşturmaktan çekinmeyin.
Bu araçla neler üreteceğinizi görmek ve deneyimlemek için sabırsızlanıyoruz.