Responsive tasarımın uzun yıllar boyunca tek koordinat sistemi viewport genişliğiydi. Bir bileşen 600 piksel ekranda farklı, 1200 pikselde farklı görünüyorsa, bu fark her zaman @media kuralıyla tanımlanırdı. Sorun şuydu: aynı bileşen dar bir sidebar'da, geniş bir hero bölümünde ve iki sütunlu bir liste düzeninde kullanıldığında üç farklı breakpoint kümesi yazmak gerekiyordu; bu kurallar zamanla birbirini geçersiz kılmaya başlardı ve bileşen gerçekte hangi alanda göründüğünden bağımsız hale gelirdi.

Container queries bu soruyu farklı bir yönden yanıtlar. "Ekran ne kadar geniş?" sorusu yerine "bu bileşenin yerleştirildiği alan ne kadar geniş?" sorusunu sorar. CSS @container kuralı, bileşeni kendi bağlamına kilitler; dışarıda ne olduğunu değil, içinde bulunduğu kutunun boyutunu takip eder. Bileşen nereye yerleştirilirse yerleştirilsin, kendi kurallarını taşır.

Performans cephesinde bu değişiklik daha derin bir sonuç doğurur. Viewport media queries, CSS motorunun zaten hesapladığı bir değeri yeniden kullanır; ek maliyet ihmal edilebilir düzeydedir. Container'a duyarlı düzenler eski yöntemde JavaScript ile kurulurdu: ResizeObserver veya window.resize dinleyicileri her boyut değişiminde DOM'u okur, sınıf ekler, stil günceller. Bu zincirleme işlem bazen gözlemlenebilir gecikmelere, bazen layout thrashing'e dönüşür. CSS container queries bu döngüyü keser.

Container Query Sözdizimi ve Temel Mekanik

Bir container query çalışmadan önce, sorgulanacak öğenin açıkça bir container olarak tanımlanması gerekir. İki özellik yeterlidir:

.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

container-type: inline-size yalnızca yatay boyutu izler. Bu ayrım önemlidir: dikey boyut takibi çok daha pahalıdır ve pratikte nadiren gerekir. container-name isteğe bağlıdır; birden fazla iç içe container varsa hangi üst öğeye soru yöneltildiğini netleştirir, isim verilmeyen bir container'da tarayıcı en yakın uygun üst öğeyi seçer.

Sorgu şöyle yazılır:

@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

Tarayıcı bu kuralı yalnızca .card-wrapper öğesi 400 pikselden geniş olduğunda uygular. .card-wrapper bir flexbox satırının üçte birini kaplıyor olabilir; ekran genişliği 1400 piksel olsa da container 350 piksel kalabilir ve kural devreye girmez. Aynı kural, aynı bileşen geniş bir ana alanda kullanıldığında ve container 450 piksele ulaştığında çalışır. Global bir media query bu ayrımı yapamaz.

Tarayıcı bu hesabı, layout aşamasında zaten ürettiği boyut bilgilerini yeniden kullanarak gerçekleştirir. JavaScript çalışma zamanına gerek yoktur; ayrı bir hesaplama döngüsü başlatılmaz.

JavaScript resize Dinleyicisinin Performans Maliyeti

Bir bileşenin boyutuna göre stil uygulamak için JavaScript yolu şöyle görünürdü:

const observer = new ResizeObserver(entries => {
  for (const entry of entries) {
    const width = entry.contentRect.width;
    entry.target.classList.toggle('is-wide', width >= 400);
  }
});
observer.observe(document.querySelector('.card-wrapper'));

Kod makul görünse de her resize olayı bir JavaScript callback'i tetikler. Callback DOM'dan boyut bilgisi okur, bu işlem layout bilgisine erişim demektir ve tarayıcıyı zaman zaman layout hesabına zorlar. Ardından sınıf değişikliği yapılır, stil hesabı tetiklenir, tarayıcı yeniden layout ve repaint aşamasına girer. Bu döngünün adı layout thrashing'dir; özellikle aynı anda birden fazla bileşen gözlemlendiğinde birikir.

Sayfada 20 kart bileşeni olduğunu varsayın. Her biri ResizeObserver ile izleniyor. Kullanıcı pencereyi yeniden boyutlandırıyor: 20 callback çalışır, 20 sınıf değişimi yapılır, tarayıcı ardından layout hesaplar. Animasyonlu pencere boyutlandırmasında bu akış kare başına birden fazla kez tekrarlanabilir. Çoğu durumda bu fark hissedilmez, ama bileşen sayısı arttıkça ana iş parçacığı üzerindeki baskı görünür hale gelir.

CSS container queries bu maliyet zincirini ortadan kaldırır. Tarayıcı layout hesabını tamamladıktan sonra hangi container query kurallarının tetikleneceğini aynı geçişte belirler; ayrı bir JavaScript yürütme döngüsü açılmaz, main thread boş kalır.

Render Hattındaki Gerçek Yer

CSS container queries, tarayıcının render hattının hangi noktasına oturur? Sıra şöyle işler: stil hesabı, layout, container query eşleştirmesi, etkilenen öğelerin yeniden stil hesabı, repaint. Container queries layout'tan sonra çalışır, çünkü container'ın boyutu ancak layout tamamlandığında bilinir.

Bedava değildir. Bu sıra, bir container query tetiklendiğinde tarayıcının kısmi olarak iki kez stil hesabı yaptığı anlamına gelir. Viewport media queries bu ikinci geçişi gerektirmez; ekran boyutu layout'tan bağımsızdır ve baştan bilinir. Container queries her zaman bu ek adımı içerir.

Ek adım genellikle küçük bir maliyettir. Karşı tarafta JavaScript alternatifinin getirdiği yük çok daha büyüktür. Seçim iki seçenek arasındadır: "ek CSS geçişi" veya "JavaScript çalışma zamanı artı layout thrashing potansiyeli". İlki çoğu durumda daha hafiftir. Bir sayfada az sayıda container query varsa ve layout değişiklikleri küçükse, bu ek geçişin maliyeti profil araçlarında dahi görünmeyebilir.

CSS contain özelliğiyle bağlantı da buradan kurulur. container-type: inline-size arka planda contain: inline-size değerini ima eder. Bu, ilgili öğenin layout hesabını çevresinden yalıtır; tarayıcı sadece o container'ı ve içindekileri yeniden hesaplayabilir. Büyük DOM ağaçlarında bu yalıtım, geniş çaplı layout yeniden hesaplamalarını önler.

Ne Zaman Kullanmak Doğrudur?

Yeniden kullanılabilir bileşenler container queries'in en verimli olduğu yerdir. Aynı kart bileşeni bir ürün listesinde, bir sidebar'da ve bir modal içinde kullanılıyorsa, her yerleşim kendi container genişliğini bildirir; bileşen kendi kurallarını taşır. Tüm düzeni saran global media query'lere gerek kalmaz, bileşen taşındığında kural takımını da taşımış olursunuz.

Design system bileşenleri için özellikle değerlidir. Bir bileşen kendi container query kurallarıyla bir npm paketi olarak dağıtıldığında, onu kullanan ekip breakpoint koordinasyonu yapmak zorunda kalmaz. Bileşen nereye yerleştirilirse yerleştirilsin doğru düzeni bulur; kullanan projenin viewport breakpoint'lerine bağımlılık ortadan kalkar.

Widget tabanlı dashboard'lar da iyi bir kullanım alanıdır. Kullanıcının widget'ları sürükleyip bıraktığı, boyutlarının dinamik olarak değiştiği arayüzlerde her widget için ResizeObserver yazmak yerine, her widget kendi container'ı içinde stilleri yönetir. İş parçacığı üzerindeki baskı azalır, kod tabanı sadeleşir.

Formların ve veri tablolarının sıkıştırılmış alanlarda görüntülendiği durumlarda da container queries temiz bir çözüm sunar. Bir tablo bileşeni daraldığında bazı sütunları gizlemek, etiketleri kısaltmak veya düzeni dikey çevirmek için viewport bilgisi yetersiz kalır; container genişliği doğrudan bu kararı verir.

Ne Zaman Gereksizdir veya Ters Etki Yapar?

Yalnızca global breakpoint'ler yeterliyse container queries ekstra karmaşıklık ekler. Sitenin düzeni viewport genişliğine tamamen bağlıysa ve bileşenler hiçbir zaman farklı bağlamlarda kullanılmıyorsa, media queries daha basit ve daha az işlem gerektirir. Araç işi gerektirdiği yerde kullanılır; her projede geçerli bir standart yoktur.

container-type: size dikkatli kullanılmalıdır. Hem yatay hem dikey boyutu izlemek, her iki eksende de containment gerektirir; bu, yüksekliğin içerik tarafından belirlenmesine dayanan bazı layout kalıplarını bozar. Dikey sorgulara çok nadir ihtiyaç duyulur; çoğu durumda inline-size yeterlidir ve daha az yan etki üretir.

İç içe container sayısı çok arttığında profil almak önemlidir. Beş ya da daha fazla iç içe container'ın hepsi aynı anda tetikleniyorsa, her biri ek bir stil hesabı geçişi başlatır ve bu maliyet birikir. Yüzeysel ölçüm bu farkı göstermeyebilir; gerçek kullanım senaryosunu profil aracıyla izlemek, tahmin üzerinden karar vermekten daha güvenilirdir.

Web component'lerde içerik projeksiyonu (slot veya transclusion) kullanıldığında container referansı bazen beklenmedik bir üst öğeye gidebilir. container-name ile hangi container'ın sorgulandığını açıkça belirtmek bu belirsizliği giderir. İsimsiz container sorguları küçük projelerde sorun çıkarmaz; derinleştikçe isim vermek bakım kolaylığı sağlar.

Tarayıcı Desteği ve Production Kullanımı

Container queries 2023 başından itibaren tüm büyük tarayıcıların kararlı sürümlerinde desteklenmektedir. Chromium tabanlı tarayıcılar, Firefox ve Safari bu özelliği eksiksiz destekler; küresel kapsama oranı 2024 ortası itibarıyla yüzde doksanın üzerindedir. Yeni bir projede polyfill gerektirmeden kullanılabilir düzeye gelmiştir.

Eski tarayıcıları desteklemek gerekiyorsa @supports ile koşullu kullanım temiz bir yol sunar:

@supports (container-type: inline-size) {
  .card-wrapper {
    container-type: inline-size;
  }
}

/* Eski tarayıcılar için media query tabanlı fallback */
@media (min-width: 640px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

JavaScript tabanlı polyfill teknik olarak vardır, ancak bu seçenek container queries'in çözdüğü sorunların bir kısmını yeniden üretir. Production'da gerçek tarayıcı desteğine güvenmek ve eski tarayıcılar için media query tabanlı fallback yazmak çoğu durumda daha temiz bir yaklaşımdır; polyfill bir geçiş aracıdır, uzun vadeli bir çözüm değildir.

Style container queries, yani @container style(...) sözdizimi, CSS özellik değerlerine göre sorgulama yapar; boyuta değil. Bu varyant farklı bir kullanım alanına hitap eder, deneysel aşamadadır ve boyut tabanlı container queries ile aynı performans profilini taşımaz. İkisini karıştırmamak, beklentilerin doğru kurulması açısından önemlidir.

Container queries aynı zamanda karmaşık media query kombinasyonlarını sadeleştirir. (min-width: 768px) and (max-width: 1200px) gibi zincirleme kurallar yerine bileşen kendi genişliğini sorar; hangi ekran boyutunda hangi sütun düzeninin uygulanacağını izleme yükü ortadan kalkar. Stil mantığı bileşende toplanır, proje genelinde dağılmaz.

JavaScript resize dinleyicisi yerine CSS container queries main thread yükünü azaltır ve layout thrashing riskini keser. Ek stil hesabı geçişinin maliyeti bu kazanımların yanında küçük kalır. Bileşen yerleştirildiği alana göre uyum sağlamalıysa container query doğal seçimdir; tam sayfa layout değişikliğinde media query daha az yük taşır.