Kapsayıcı sorgusu polyfill içinde

Gerald Monaco
Gerald Monaco

Kapsayıcı sorguları, bir üst öğenin özelliklerini (örneğin, genişliği veya yüksekliği) hedefleyerek alt öğelerinin stilini belirleyen yeni bir CSS özelliğidir. Kısa süre önce, tarayıcılara yönelik destek açılışıyla aynı zamana denk gelen polyfill işlevinde büyük bir güncelleme kullanıma sunuldu.

Bu yayında, çoklu dolgunun nasıl çalıştığına, üstesinden geldiği zorluklara ve ziyaretçilerinize mükemmel bir kullanıcı deneyimi sunmak için onu kullanmayla ilgili en iyi uygulamalara göz atabileceksiniz.

Gelişmiş seçenekler

Terleme

Bir tarayıcı içindeki CSS ayrıştırıcısı, yepyeni bir kuralla (ör. yepyeni @container) karşılaştığında bilinmeyen bir kuralla karşılaşır ve bu kuralı hiç varmış gibi siler. Bu nedenle, çoklu dolgunun yapması gereken ilk ve en önemli şey bir @container sorgusunu atılmayacak bir şeye dönüştürmektir.

Aktarmada ilk adım, üst düzey @container kuralını bir @media sorgusuna dönüştürmektir. Bu, çoğunlukla içeriğin grup halinde kalmasını sağlar. Örneğin, CSSOM API'lerini kullanırken ve CSS kaynağını görüntülerken.

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

Kapsayıcı sorgularından önce CSS'de yazarın kural gruplarını rastgele etkinleştirip devre dışı bırakabileceği bir yöntem yoktu. Bu davranışa çoklu dolgu yapmak için kapsayıcı sorgusunun içindeki kuralların da dönüştürülmesi gerekir. Her @container öğesine kendi benzersiz kimliği (örneğin, 123) verilir. Bu kimlik, her seçiciyi yalnızca öğe bu kimliği içeren bir cq-XYZ özelliğine sahip olduğunda uygulanacak şekilde dönüştürmek için kullanılır. Bu özellik, çalışma zamanında polyfill 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ımına dikkat edin. Normalde, ek bir özellik seçici eklemek seçicinin spesifikliğini artırır. Sözde sınıf kullanıldığında, ekstra koşul ancak orijinal özgüllük korunarak uygulanabilir. Bunun neden önemli olduğunu görmek için aşağıdaki örneği inceleyin:

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

.card {
  color: red;
}

Bu CSS göz önüne alındığında, .card sınıfına sahip bir öğe her zaman color: red değerine sahip olmalıdır. Çünkü sonraki kural, her zaman aynı seçici ve belirlilikle önceki kuralı geçersiz kılar. Bu nedenle, ilk kuralın başka bir dile çevrilmesi ve :where(...) olmadan ek bir özellik seçicinin eklenmesi, doğruluğu artırır ve color: blue uygulamasının hatalı bir şekilde uygulanmasına neden olur.

Ancak, :where(...) sözde sınıfı oldukça yenidir. Çoklu dolgu, bu özelliği desteklemeyen tarayıcılar için güvenli ve kolay bir çözüm sağlar: @container kurallarınıza manuel bir :not(.container-query-polyfill) seçici ekleyerek kurallarınızın belirginliğini bilerek 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;
}

Bunun bir dizi avantajı vardır:

  • Kaynak CSS'deki seçici değiştiğinden aradaki fark açıkça görülebilir. Bu, aynı zamanda bir doküman görevi görür. Böylece, artık geçici çözümü veya çoklu dolguyu desteklemenize gerek kalmadığında nelerin etkilendiğini bilirsiniz.
  • Çoklu dolguyu değiştirmediği için kuralların kesinliği her zaman aynı olacaktır.

Çevirileme sırasında çoklu dolgu, bu temsili, aynı kesinliğe sahip özellik seçiciyle değiştirir. Çoklu dolgu, sürprizlerle karşılaşmamak için her iki seçiciyi de kullanır: Öğenin polyfill özelliğini alıp almayacağını belirlemek için orijinal kaynak seçici kullanılır ve stil eklemek için çevrilen seçici kullanılır.

Sözde öğeler

Kendinize sorabileceğiniz sorulardan biri şu olabilir: Çoklu dolgu, bir öğede 123 benzersiz kapsayıcı kimliğini içerecek şekilde bazı cq-XYZ özelliklerini ayarlıyorsa, özellikleri ayarlayamayacak yapay öğeler nasıl desteklenebilir?

Sözde öğeler, her zaman DOM'da kaynak öğe olarak adlandırılan gerçek bir öğeye bağlıdır. Çevirileme sırasında, koşullu seçici 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"]) değerine dönüştürülmek yerine (geçersiz olur) #foo kaynak öğenin sonuna taşınır.

Ancak tüm bunlar yeterli değil. Bir kapsayıcının, içinde olmayan herhangi bir şeyi değiştirmesine izin verilmez (ve bir kapsayıcı kendi içinde olamaz). Ancak, sorgulanan kapsayıcı öğenin kendisi #foo olsaydı tam olarak bu olacağını düşünün. #foo[cq-XYZ] özelliği hatalı bir şekilde değiştirilecek ve tüm #foo kuralları hatalı bir şekilde uygulanacaktı.

Bunu düzeltmek için çoklu dolgu aslında iki özellik kullanır: Bir öğeye yalnızca bir üst öğe tarafından uygulanabilecek bir özellik ve bir öğenin kendisine uygulayabileceği bir özellik. İkinci ö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) kendisine hiçbir zaman uygulamayacağı için ilk seçici yalnızca farklı bir üst kapsayıcı, kapsayıcı koşullarını karşılayıp uyguladığında eşleşir.

Container göreli birimleri

Kapsayıcı sorguları, CSS'de kullanabileceğiniz birkaç yeni birim de sunar. Örneğin, en yakın uygun üst kapsayıcının genişlik ve yüksekliğinin% 1'i için cqw ve cqh gibi. Bunları desteklemek için birim CSS Özel Özellikleri kullanılarak bir calc(...) ifadesine dönüştürülür. Çoklu dolgu, bu özelliklerin değerlerini kapsayıcı öğesindeki satır içi stiller aracılığıyla 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 eksenler sorgulanan öğeye değil, birimi kullanan öğenin writing-mode parametresine göre belirlendiğinden bunlar biraz daha karmaşıktır. Bunu desteklemek için çoklu dolgu, writing-mode öğesi üst öğesinden farklı olan tüm öğelere bir 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 daha önce olduğu gibi uygun CSS Özel Mülküne dönüştürülebilir.

Özellikler

Kapsayıcı sorguları ayrıca 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 ayrıştırıldıktan sonra da CSS Özel Özellikleri'ne dönüştürülür. Bir özellik ayrıştırılamazsa (örneğin, geçersiz veya bilinmeyen bir değer içerdiği için) tarayıcının işleyebilmesi için tek başına 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;
}

Keşfedildiğinde bu özellikler dönüştürülerek çoklu dolgunun @supports gibi diğer CSS özellikleriyle düzgün şekilde çalışmasını sağlar. Bu işlev, aşağıda açıklandığı gibi çoklu dolguyu kullanmaya yönelik en iyi uygulamaların temelini oluşturur.

Önce
@supports (container-type: inline-size) {
  /* ... */
}
Sonra
@supports (--cq-XYZ-container-type: inline-size) {
  /* ... */
}

Varsayılan olarak CSS Özel Özellikleri devralınır. Örneğin, .card öğesinin herhangi bir alt öğesi --cq-XYZ-container-name ve --cq-XYZ-container-type değerini alır. Yerel özelliklerin davranışı kesinlikle bu şekilde değildir. Bu sorunu çözmek için çoklu dolgu, aşağıdaki kuralı tüm kullanıcı stillerinden önce ekler. Böylece, başka bir kural tarafından özellikle 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 bir süre sonra yerleşik kapsayıcı sorgu destekli tarayıcılar kullanmaya başlaması beklense de geri kalan ziyaretçilerinize iyi bir deneyim sunmanız önemlidir.

İlk yükleme sırasında, çoklu dolgunun sayfayı yerleştirebilmesi için çok fazla işlem yapılması gerekir:

  • Çoklu dolgunun yüklenmesi ve başlatılması gerekir.
  • Stil sayfalarının ayrıştırılması ve dönüştürülmesi gerekir. Harici bir stil sayfasının ham kaynağına erişmek için herhangi bir API bulunmadığından, ideal olarak yalnızca tarayıcı önbelleğinden olsa da eşzamanlı olmadan yeniden getirilmesi gerekebilir.

Çoklu dolgu tarafından bu endişeler dikkatlice giderilmezse Önemli Web Verileri geri alınabilir.

Çoklu dolgu, ziyaretçilerinize iyi bir deneyim sunmanızı kolaylaştırmak için İlk Giriş Gecikmesi (FID) ve Cumulative Layout Shift (CLS) önceliklendirmesi için tasarlandı. Bu durum, muhtemelen Largest Contentful Paint (LCP) gereksinimini ortadan kaldırır. Daha net ifade etmek gerekirse çoklu dolgu, container sorgularınızın ilk boyamadan önce değerlendirileceğini garanti etmez. Diğer bir deyişle, en iyi kullanıcı deneyimi için, kapsayıcı sorgularının kullanılmasından boyutu veya konumu etkilenecek olan tüm içeriklerin, çoklu dolgu CSS'niz yüklenip aktarılana 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 şey olduğunu belirtmek için (gizli) içeriğinizin üzerinde kesinlikle konumlandırılmış bir CSS yükleme animasyonu ile birleştirmeniz önerilir. Bu yaklaşımın eksiksiz bir demosunu burada bulabilirsiniz.

Bu yaklaşım, birkaç nedenden dolayı önerilir:

  • Sadece CSS yükleyici, yeni tarayıcılara sahip kullanıcılar için ek yükü en aza indirirken, eski tarayıcılardaki ve daha yavaş ağlardaki kullanıcılara hafif geri bildirim sağlar.
  • Yükleyicinin mutlak konumlandırmasını visibility: hidden ile birleştirerek düzen kaymasını önlersiniz.
  • Çoklu dolgu yüklendikten sonra bu @supports koşulu artık kullanılamayacak ve içeriğiniz gösterilecektir.
  • Container sorguları için yerleşik desteğe sahip tarayıcılarda koşul hiçbir zaman geçilmez ve bu nedenle sayfa beklendiği gibi ilk boyamada görüntülenir.

Sonuç

Kapsayıcı sorgularını eski tarayıcılarda kullanmak istiyorsanız polyfill'i deneyin. Herhangi bir sorunla karşılaşırsanız sorun göndermekten çekinmeyin.

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

Teşekkür

Dan Cristian Pădure İs tarafından Unsplash'ta yayınlanan hero resim.