Kapsayıcı sorgusu polyfill içinde

Gerald Monaco
Gerald Monaco

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ılara sunulan destekle aynı zamanda çoklu dolguda yapılan 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ı içindeki CSS ayrıştırıcısı, yepyeni @container kuralı gibi bilinmeyen bir kuralla karşılaştığında, bu kuralı hiç varmış gibi siler. Bu nedenle, polyfill'in yapması gereken ilk ve en önemli şey, bir @container sorgusunu atılmayacağı bir şeye dönüştürmektir.

Transpilasyonda 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.

Önce
@container (width > 300px) {
  /* content */
}
Sonra
@media all {
  /* content */
}

Kapsayıcı sorgularından önce, CSS'de yazarların kural gruplarını rastgele etkinleştirebileceği veya devre dışı bırakabileceği bir yöntem bulunmuyordu. 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 (örneğin, 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 çoklu dolgu tarafından ayarlanır.

Önce
@container (width > 300px) {
  .card {
    /* ... */
  }
}
Sonra
@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çicinin eklenmesi, seçicinin spesifikliğini artırır. Sanal sınıf ile ekstra koşul, orijinal özgünlük korunurken 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 göz önünde bulundurulduğunda, .card sınıfına sahip bir öğe her zaman color: red içermelidir. Çünkü sonraki kural, önceki kuralı her zaman aynı seçici ve kesinlikle 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:

Önce
@container (width > 300px) {
  .card {
    color: blue;
  }
}

.card {
  color: red;
}
Sonra
@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.

Aktarma sırasında çoklu dolgu, bu temsili aynı belirginliğe sahip ö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?

Sözde öğeler her zaman DOM'deki kaynak öğe adı verilen gerçek bir öğeye bağlıdır. Koşullu seçici, derleme sırasında bunun yerine bu gerçek öğeye uygulanır:

Önce
@container (width > 300px) {
  #foo::before {
    /* ... */
  }
}
Sonra
@media all {
  #foo:where([cq-XYZ~="123"])::before {
    /* ... */
  }
}

Koşullu seçici, #foo::before:where([cq-XYZ~="123"]) biçimine dönüştürülmek (bu durum geçersiz olur) yerine #foo kaynak öğesinin sonuna taşınır.

Ancak bununla da yetinilmez. Bir kapsayıcının içinde bulunmayan hiçbir şeyi değiştirmesine izin verilmez (ve bir kapsayıcı kendi içinde bulunamaz). 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. Sonraki özellik, sözde öğeleri hedefleyen seçiciler için kullanılır.

Önce
@container (width > 300px) {
  #foo,
  #foo::before {
    /* ... */
  }
}
Sonra
@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 uygulamayacağı için ilk seçici, yalnızca kapsayıcı koşullarını karşılayıp farklı bir üst kapsayıcı tarafından uygulanmışsa 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. Bunları desteklemek için birim, CSS Özel Özellikleri kullanılarak 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.

Önce
.card {
  width: 10cqw;
  height: 10cqh;
}
Sonra
.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 eskiden olduğu 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ılamadığından bunlar da ayrıştırıldıktan sonra CSS Özel Özellikleri'ne dönüştürülür. Bir özellik ayrıştırılamıyorsa (örneğin, geçersiz veya bilinmeyen bir değer içerdiği için) tarayıcının işlemesi için yalnız bırakılır.

Önce
.card {
  container-name: card-container;
  container-type: inline-size;
}
Sonra
.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ığı şekilde, çoklu dolguyu kullanmayla ilgili en iyi uygulamaların temelini oluşturur.

Önce
@supports (container-type: inline-size) {
  /* ... */
}
Sonra
@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. Somut bir şekilde ifade etmek gerekirse çoklu dolgu, container sorgularınızın ilk boyadan önce değerlendirileceğini garanti etmez. 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, birkaç nedenden dolayı önerilir:

  • 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ını önlersiniz.
  • 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ı kullanmak istiyorsanız polyfill'i deneyin. Herhangi bir sorunla karşılaşırsanız sorun kaydı oluşturmaktan çekinmeyin.

YouTube Create ile geliştireceğiniz muhteşem şeyleri görmek ve deneyimlemek için sabırsızlanıyoruz.