React’te Responsive Davranışı JS’e Taşımadan Çözmek: Container Queries + ResizeObserver ile Akıllı Bileşenler
Bileşenleri ekran yerine konteynıra göre uyarlayın: CSS Container Queries ve gerektiğinde ResizeObserver ile.
React projelerinde responsive tasarım çoğu zaman “ekran genişliği”ne (media queries) bağlanır. Ancak modern UI’lar artık kartlar, paneller, yan barlar, modal’lar gibi farklı konteynırlar içinde çalışıyor. Aynı bileşen, farklı yerlerde farklı genişlikler görebiliyor. Bu noktada Container Queries devreye giriyor: Bileşen, kendi konteynırının boyutuna göre şekil değiştirebiliyor.
Aşağıda, React’te bu yaklaşımı JS’e boğmadan nasıl uygulayabileceğinizi ve gerektiğinde ResizeObserver ile nasıl güvenli bir fallback ekleyebileceğinizi anlatıyorum.
1) CSS Container Queries ile bileşeni “konteynıra duyarlı” yapmak
Önce konteynıra container-type tanımlayarak başlarız. Bu, içindeki elemanların konteynır boyutuna göre sorgu yazabilmesini sağlar.
/* container.css */
.panel {
container-type: inline-size; /* genişlik bazlı container query */
container-name: panel;
border: 1px solid #e5e7eb;
padding: 16px;
}
.card {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
/* Konteynır 520px ve üstüne çıkınca iki kolon */
@container panel (min-width: 520px) {
.card {
grid-template-columns: 160px 1fr;
align-items: start;
}
.card__thumb {
aspect-ratio: 1 / 1;
}
}
.card__thumb {
background: #f3f4f6;
border-radius: 10px;
aspect-ratio: 16 / 9;
}
.card__title {
font-weight: 600;
}
.card__meta {
color: #6b7280;
font-size: 14px;
}
React tarafı basit kalır:
import "./container.css";
export function ProductCard({ title, meta }) {
return (
<section className="panel">
<article className="card">
<div className="card__thumb" />
<div>
<div className="card__title">{title}</div>
<div className="card__meta">{meta}</div>
</div>
</article>
</section>
);
}
Bu yaklaşımın güzelliği: Aynı ProductCard, ister dar bir sidebar’da ister geniş bir ana içerikte olsun, kendi konteynırına göre otomatik düzen değiştirir.
2) “Breakpoint” mantığını bileşen bazında standardize etmek
Media query’lerde genelde global breakpoint’ler olur. Container query ile bileşen bazında mini breakpoint’ler tanımlayabilirsiniz:
- Kart: 520px → iki kolon
- Tablo satırı: 700px → ekstra sütunlar
- Filtre paneli: 360px → ikon + metin, altı → sadece ikon
Bu sayede tasarım sistemi daha modüler olur.
3) Gerekli olduğunda: ResizeObserver ile JS fallback (progressive enhancement)
Her şeyi CSS ile çözmek ideal; ama bazen React içinde “konteynır dar ise tooltip aç”, “dar ise metni kısalt” gibi davranışsal kararlar gerekir.
Aşağıdaki hook, bir elementin genişliğini izler:
import { useEffect, useRef, useState } from "react";
export function useElementWidth() {
const ref = useRef(null);
const [width, setWidth] = useState(0);
useEffect(() => {
if (!ref.current) return;
const el = ref.current;
const ro = new ResizeObserver(([entry]) => {
setWidth(Math.round(entry.contentRect.width));
});
ro.observe(el);
return () => ro.disconnect();
}, []);
return { ref, width };
}
Kullanım:
import "./container.css";
import { useElementWidth } from "./useElementWidth";
export function ProductCard({ title, meta }) {
const { ref, width } = useElementWidth();
const isCompact = width > 0 && width < 360;
return (
<section ref={ref} className="panel">
<article className="card">
<div className="card__thumb" />
<div>
<div className="card__title">
{isCompact ? title.slice(0, 24) + "…" : title}
</div>
<div className="card__meta">{meta}</div>
</div>
</article>
</section>
);
}
Burada layout değişimi CSS Container Queries ile, metin kısaltma gibi UI davranışı ise gerektiğinde JS ile çözülüyor. Böylece React render döngüsünü gereksiz yere “window resize” event’leriyle yormazsınız.
4) Pratik ipuçları
container-type: inline-sizeçoğu senaryoda yeterli (genelde genişliğe bakıyoruz).- Konteynır adını (
container-name) vermek, büyük projelerde okunabilirliği artırır. - Bileşenleri “sayfaya” değil “konteynıra” göre tasarlamak, yeniden kullanım oranını ciddi artırır.
Sonuç
React’te responsive tasarımı sadece “ekran”a bağlamak artık kısıtlayıcı. Container Queries ile bileşenler, bulundukları alanın koşullarına uyum sağlar. Davranışsal kararlar gerekiyorsa ResizeObserver ile küçük bir hook ekleyip progressive enhancement yaklaşımıyla ilerleyebilirsiniz.