Skip to content

Bölüm 10 / 20

Grid

İki boyutlu yerleşim.

13 dakikalık okuma

Flexbox tek eksende çalışır: ya bir satır ya bir sütun. Sayfa iskeleti, kart ızgarası ve form hizalaması gibi işlerde ise satır ve sütunun aynı anda hizalanması gerekir. Grid bunun için tasarlanmış ilk gerçek CSS yerleşim sistemidir ve Flexbox'tan farklı bir yönden çalışır: önce ızgarayı sen tanımlarsın, sonra içerik hücrelere yerleşir. Bu ders fr biriminden grid-template-areas'a, auto-fill ile auto-fit arasındaki gerçek farktan medya sorgusu yazmadan duyarlı ızgara kurmaya kadar Grid'in tamamını ele alıyor.

01Ne öğreneceksin

  • Izgara sözlüğü: hat (line), iz (track), hücre, alan
  • grid-template-columns/rows ve fr birimi gerçekte nasıl hesaplanır
  • repeat(), minmax() ve auto-fill ile auto-fit farkı
  • Medya sorgusu yazmadan duyarlı kart ızgarası
  • Yerleştirme: hat numarası, span, hat adları, grid-template-areas
  • Hizalama altı özelliği ve place-* kısayolları
  • Örtük ızgara: grid-auto-rows, grid-auto-flow, dense
  • Tuzak: 1fr'nin taban boyutu auto'dur — minmax(0, 1fr) ne zaman gerekir
  • Aynı hücrede üst üste bindirme (position: absolute'a alternatif)
  • subgrid ile iç ögelerin dış ızgaraya hizalanması
  • Grid ile tablo farkı ve erişilebilirlik sınırı

02Izgara sözlüğü

      1        2        3        4     ← sütun hatları (grid line)
    1 ┌────────┬────────┬────────┐
      │  hücre │        │        │   ← iz (track) = iki hat arası
    2 ├────────┼────────┼────────┤
      │        │   alan (area)   │   ← birden çok hücrenin dikdörtgeni
    3 └────────┴────────┴────────┘
      ↑ satır hatları

Dikkat: numaralanan şey hücreler değil hatlardır. Üç sütunlu bir ızgarada dört sütun hattı vardır. Yerleştirme yaparken grid-column: 1 / 3 yazdığında "1. hattan 3. hatta kadar", yani iki sütun genişliğinde demiş olursun. Bu, Grid'i ilk öğrenirken en çok yanılgı üreten noktadır.

.kapsayici { display: grid; }         /* blok düzeyinde ızgara */
.kapsayici { display: inline-grid; }  /* metin akışında duran ızgara */

03İzleri tanımlamak

.izgara {
  display: grid;
  grid-template-columns: 200px 1fr 300px;   /* üç sütun */
  grid-template-rows: auto 1fr auto;        /* üç satır */
  gap: 1rem;
}
DeğerAnlamı
200px, 10remSabit
autoİçeriğe göre; kalan boşluk varsa büyüyebilir
min-contentEn uzun kelime kadar
max-contentHiç sarmadan gereken genişlik
fit-content(300px)İçeriğe göre, ama en fazla 300 px
1frKalan boşluğun bir payı
minmax(200px, 1fr)En az 200 px, en çok bir pay

fr birimi gerçekte ne yapar

fr "fraction" — kalan boşluğun kesridir. 1fr 2fr yazarsan kalan boşluk 1:2 oranında bölünür. Ama bilinmesi gereken önemli bir ayrıntı vardır:

1fr aslında minmax(auto, 1fr) demektir. Yani izin taban boyutu auto'dur ve içeriğinden daha dar olamaz. 9. derste Flexbox'ta gördüğün min-width: auto tuzağının Grid'deki karşılığı budur:

.izgara { grid-template-columns: 1fr 1fr; }
/* İçlerinden birinde uzun bir URL ya da geniş bir tablo varsa,
   o sütun "1fr"e rağmen daralmaz ve ızgara taşar. */

.izgara { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }   /* çözüm */
/* ya da öge tarafında: .hucre { min-width: 0; overflow: hidden; } */

Kaydırılabilir bir bölgeyi bir ızgara hücresine koyduğunda da aynı şey gerekir; aksi hâlde hücre kaydırılmak yerine büyür.

repeat(), auto-fill ve auto-fit

grid-template-columns: repeat(4, 1fr);            /* 1fr 1fr 1fr 1fr */
grid-template-columns: repeat(2, 200px 1fr);      /* desen tekrarı */
grid-template-columns: 200px repeat(3, 1fr) 100px; /* karışık */

Asıl güç, repeat()'in sayı yerine anahtar kelime almasındadır:

/* MEDYA SORGUSU YOK — sütun sayısına tarayıcı karar verir */
.kartlar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
}

Okunuşu: "en az 260 px, en çok bir pay olan sütunlardan sığdığı kadar aç." Pencere daraldıkça sütun sayısı 4 → 3 → 2 → 1'e düşer. Bu tek satır, eskiden beş medya sorgusu gerektiren işi yapar.

auto-fillauto-fit
Sığan sütun sayısı kadar iz açarEvetEvet
Boş kalan izlerKorunur — yer kaplarDaraltılıp yok edilir
3 kart, 5 sütunluk yer varsaKartlar solda kalır, sağda 2 boş sütun dururKartlar genişleyip tüm satırı doldurur
Ne zamanIzgara hizası korunsun isteniyorsa (satırlar arası sütunlar hizalı kalsın)Az sayıda öge boşluğu doldursun isteniyorsa — genelde istenen budur

Fark yalnızca ögeler sütun sayısından az olduğunda görünür; eleman sayısı fazlaysa ikisi aynı sonucu verir. Bu, mülakatta bilgi derinliğini ölçen tipik bir ayrıntıdır.

04Ögeleri yerleştirmek

Bir şey yazmazsan ögeler hücrelere sırayla, soldan sağa ve yukarıdan aşağıya yerleşir. Yerleştirmeyi elle yapmanın üç yolu vardır.

1. Hat numarasıyla

.baslik  { grid-column: 1 / 4; }        /* 1. hattan 4. hatta → üç sütun */
.baslik  { grid-column: 1 / -1; }       /* -1 = SON hat → "tüm satırı kapla" */
.icerik  { grid-column: span 2; }       /* bulunduğu yerden iki sütun */
.kutu    { grid-row: 2 / 4; }           /* satırlarda aynı mantık */

.kutu    { grid-area: 2 / 1 / 4 / 3; }  /* satır-baş / sütun-baş / satır-son / sütun-son */

-1 kısayolu çok kullanılır: bir başlığın ya da tam genişlikte bir uyarı kutusunun sütun sayısından bağımsız olarak satırı kaplaması için grid-column: 1 / -1 yeterlidir.

2. Hat adlarıyla

.duzen {
  display: grid;
  grid-template-columns: [kenar-bas] 240px [icerik-bas] 1fr [icerik-son] 300px [kenar-son];
}
.icerik { grid-column: icerik-bas / icerik-son; }

3. Alan adlarıyla — en okunaklısı

.sayfa {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
  grid-template-areas:
    "ustbar  ustbar"
    "yanmenu icerik"
    "altbilgi altbilgi";
}
.ustbar   { grid-area: ustbar; }
.yanmenu  { grid-area: yanmenu; }
.icerik   { grid-area: icerik; }
.altbilgi { grid-area: altbilgi; }

/* Dar ekranda yalnız haritayı değiştir — tek sütuna in */
@media (max-width: 700px) {
  .sayfa {
    grid-template-columns: 1fr;
    grid-template-areas: "ustbar" "yanmenu" "icerik" "altbilgi";
  }
}

grid-template-areas'ın değeri okunabilirliktir: yerleşimi CSS'te ASCII çizimi gibi görürsün ve duyarlı düzende yalnızca haritayı değiştirirsin. Kurallar: her alan dikdörtgen olmalıdır (L şeklinde alan tanımlanamaz), boş hücre için . yazılır ve her satırda sütun sayısı eşit olmalıdır.

Erişilebilirlik uyarısı burada da geçerlidir: 9. derste order için söylenen her şey grid-area için de doğrudur. Yukarıdaki dar ekran haritasında yanmenu'yü icerik'ten sonraya almak görsel sırayı değiştirir ama klavye ve ekran okuyucu hâlâ DOM sırasını izler. İçerik sırası anlamlıysa işaretlemeyi doğru sırada yaz.

05Hizalama: altı özellik

ÖzellikKimNeyi hizalar
justify-itemsKapsayıcıÖgeleri hücreleri içinde, yatayda
align-itemsKapsayıcıÖgeleri hücreleri içinde, dikeyde
justify-contentKapsayıcıIzgaranın tamamını kapsayıcı içinde, yatayda
align-contentKapsayıcıIzgaranın tamamını, dikeyde
justify-self / align-selfÖgeTek bir ögeyi kendi hücresinde

Ayrımı hatırlamanın yolu: -items hücrenin içi, -content ızgaranın kendisi. justify-content yalnız izlerin toplamı kapsayıcıdan küçükse (sabit genişlikli sütunlar varsa) fark yaratır; sütunlar fr ile tanımlıysa boşluk zaten kalmaz.

place-items: center;               /* align-items + justify-items */
place-content: center;             /* align-content + justify-content */
place-self: center;                /* align-self + justify-self */

/* Bir şeyi tam ortalamanın en kısa yolu */
.orta { display: grid; place-items: center; min-height: 100dvh; }

Flexbox'la karşılaştırıldığında Grid'in avantajı burada da görünür: Flexbox'ta justify-items yoktur, çünkü tek eksende hücre kavramı yoktur.

06Örtük ızgara

Tanımladığından fazla öge gelirse Grid yeni izler üretir; bunlara örtük ızgara denir ve boyutları varsayılan olarak auto'dur:

.izgara {
  grid-template-columns: repeat(3, 1fr);   /* açık: 3 sütun */
  grid-auto-rows: minmax(120px, auto);     /* örtük satırlar en az 120 px */
  grid-auto-flow: row;                     /* varsayılan: satır satır doldur */
}

.galeri { grid-auto-flow: dense; }   /* boşlukları geriye dönüp doldur */

dense farklı boyutlarda kartlar olan galerilerde delikleri kapatır ama görsel sırayı DOM sırasından koparır — yine aynı erişilebilirlik ödünü.

grid-auto-flow: column ise ögeleri sütun sütun doldurur; sütun sayısı bilinmeyen yatay listelerde işe yarar.

07Gerçek kalıplar

/* 1. Duyarlı kart ızgarası — medya sorgusu yok */
.kartlar { display: grid; gap: 1rem;
           grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* 2. Form: etiket ve alan hizalı — 4. derste "tablo kullanma" dediğimiz iş */
.form {
  display: grid;
  grid-template-columns: max-content 1fr;   /* etiketler kendi genişliğinde, hizalı */
  gap: .75rem 1rem;
  align-items: baseline;
}
.form .tam-satir { grid-column: 1 / -1; }   /* açıklama ve düğmeler tüm satırı kaplar */

@media (max-width: 600px) {                  /* dar ekranda tek sütun */
  .form { grid-template-columns: 1fr; }
}

/* 3. Aynı hücrede üst üste: position: absolute'a gerek yok */
.kapak { display: grid; }
.kapak > * { grid-area: 1 / 1; }             /* hepsi aynı hücreye */
.kapak .yazi { place-self: end start; z-index: 1; }

/* 4. "Kutsal kâse": kenarlar sabit, orta esner, altbilgi yapışık */
.iskelet { display: grid; min-height: 100dvh;
           grid-template: auto 1fr auto / 240px 1fr; }

/* 5. Kenarlıklı içerik hattı: içerik ortada, arka plan tam genişlikte */
.sayfa { display: grid; grid-template-columns: 1fr min(70ch, 100%) 1fr; }
.sayfa > * { grid-column: 2; }
.sayfa > .tam-genislik { grid-column: 1 / -1; }

İkinci kalıp, 4. derste "form yerleşimi için tablo kullanma" derken kastedilen doğru araçtır: max-content 1fr ile etiketler en uzun etikete göre hizalanır, dar ekranda tek satırla tek sütuna inersin ve işaretlemede hiçbir değişiklik gerekmez.

Üçüncü kalıp da pratik bir kazanç sağlar: üst üste bindirme için position: absolute kullandığında kapsayıcının yüksekliği içerikten bağımsızlaşır ve elle yükseklik vermen gerekir; Grid'de tüm katmanlar aynı hücrede olduğu için en uzun olan yüksekliği belirler.

subgrid

Bir ızgara ögesinin kendi çocuklarını dış ızgaranın hatlarına hizalaması gerektiğinde kullanılır. Klasik sorun: kart listesinde her kartın başlığı, metni ve düğmesi kendi içinde hizalıdır ama kartlar arasında hizalı değildir.

.kartlar { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
           grid-template-rows: auto 1fr auto; }
.kart    { display: grid; grid-row: span 3; grid-template-rows: subgrid; }
/* Artık tüm kartların başlıkları, metinleri ve düğmeleri aynı hatta hizalanır. */

subgrid tarayıcılara geç geldi; destek durumunu kontrol etmek gerekir. Desteklenmediğinde kartlar yine çalışır, sadece iç hizalama kaybolur — yani 7. derste konuştuğumuz kademeli geliştirmeye uygun bir özelliktir.

Grid tabloyu değiştirir mi?

Görsel olarak evet, anlamsal olarak hayır. Grid ile bir tablo görünümü çizebilirsin ama ekran okuyucu orada satır–sütun ilişkisi görmez: hangi değerin hangi başlığa ait olduğu duyurulmaz, hücreler arasında ok tuşlarıyla gezilemez. Veri tablosu tablodur (4. ders); Grid tabloyu değil, yerleşim tablosunu ortadan kaldırır. Buna karşılık bir tablonun kendisine display: grid vermek de yanlıştır — tablonun yerleşim semantiğini bozar ve bazı ekran okuyucularda tablo olmaktan çıkarır. Dar ekranda tabloyu kart görünümüne çevirme kararının bedeli buydu.

08Mini alıştırma — Izgarayı kur, kır, ölç

Yaklaşık 20 dakika · tek HTML dosyası + DevTools grid denetleyicisi

  1. Kur: dokuz kutulu bir ızgara yaz (grid-template-columns: repeat(3, 1fr)). DevTools'ta kapsayıcının yanındaki grid rozetine tıkla; hat numaralarını ve alan adlarını ekranda göster.
  2. Hat sayısı: üç sütunda kaç sütun hattı var? grid-column: 1 / 3 verdiğinde öge kaç sütun kapladı?
  3. -1: bir başlığa grid-column: 1 / -1 ver ve sütun sayısını 3'ten 5'e çıkar. Başlık uyum sağladı mı?
  4. fr hesabı: 200px 1fr 2fr yaz ve pencereyi daralt. Sabit sütun değişti mi, oran nasıl korundu?
  5. Tuzak: 1fr 1fr olan ızgaranın bir hücresine çok uzun bir URL yapıştır. Izgara taştı mı? minmax(0, 1fr) ile tekrarla.
  6. auto-fit vs auto-fill: repeat(auto-fit, minmax(200px, 1fr)) ile üç kart göster; pencereyi genişlet. Sonra auto-fill'e çevir. Fark ne zaman görünüyor?
  7. Alan haritası: grid-template-areas ile üst bar + yan menü + içerik + altbilgi iskeleti kur. Sonra yalnız medya sorgusunda haritayı değiştirerek tek sütuna in.
  8. Dikdörtgen kuralı: haritada L şeklinde bir alan tanımlamayı dene. DevTools ne gösteriyor?
  9. Hizalama: justify-items, align-items, justify-content, align-content değerlerini tek tek değiştir. Sabit genişlikli sütunlarda ve 1fr sütunlarda hangileri etki etti?
  10. Ortalama: display: grid; place-items: center; min-height: 100dvh ile bir kutuyu tam ortala. Flexbox'la aynı işi yapıp satır sayısını karşılaştır.
  11. Örtük ızgara: üç sütunlu ızgaraya 10 öge koy. Dördüncü satır nereden geldi? grid-auto-rows: minmax(120px, auto) ekleyip farkı gör.
  12. dense: bazı ögelere grid-column: span 2 ver, boşluk oluşsun. grid-auto-flow: dense ekle — boşluk doldu mu? Şimdi Tab ile gez; odak sırası görsel sırayla aynı mı?
  13. Form: 2. kalıptaki max-content 1fr formunu kur. En uzun etiketi uzat — sütun genişliği uyum sağladı mı?
  14. Üst üste bindirme: 3. kalıpla bir görselin üzerine yazı koy. Kapsayıcının yüksekliğini vermeden çalışıyor mu? Aynısını position: absolute ile deneyip farkı gör.

09Kendini sına

Grid ile Flexbox arasındaki fark nedir? Hangisini ne zaman kullanırsın?

Flexbox tek boyutludur: ögeleri bir eksende dizer, kalan boşluğu dağıtır. Grid iki boyutludur: satır ve sütunu aynı anda tanımlar ve ögeleri hücrelere yerleştirir. Çalışma yönleri de terstir: Flexbox içerikten yerleşime gider — ögelerin boyutunu içerikleri belirler; Grid yerleşimden içeriğe gider — ızgarayı sen tanımlarsın, içerik ona uyar. Karar ölçütü: tek eksende dizilim ve içeriğe göre boyut istiyorsan Flexbox (üst bar, düğme grubu, etiket–değer satırı, bir kartın iç dizilimi); satır ve sütun hizalaması gerekiyorsa Grid (sayfa iskeleti, kart ızgarası, form etiket–alan hizalaması). İkisi rakip değildir: tipik bir sayfada dış iskelet Grid, iç bileşenler Flexbox olur. Grid'in Flexbox'ta bulunmayan yetenekleri: grid-template-areas ile okunaklı harita, justify-items gibi hücre içi hizalama, aynı hücrede üst üste bindirme ve auto-fit/minmax ile medya sorgusuz duyarlı ızgara. Flexbox'ın avantajı ise bilinmeyen sayıda ve değişken boyutlu ögeyi tek eksende dağıtmaktır.

auto-fill ile auto-fit arasındaki fark nedir?

İkisi de repeat() içinde "sığdığı kadar sütun aç" der ve ögeler sütun sayısını dolduruyorsa aynı sonucu verir. Fark, ögeler açılan sütun sayısından az olduğunda ortaya çıkar. auto-fill boş kalan izleri korur: 5 sütunluk yerde 3 kart varsa kartlar solda kalır, sağda iki boş sütun yer kaplar. auto-fit ise boş izleri sıfıra daraltır; kalan 1fr payları mevcut kartlara gider ve kartlar genişleyip satırı doldurur. Pratikte genelde istenen auto-fit'tir (repeat(auto-fit, minmax(260px, 1fr))) — az sayıda öge olduğunda düzen boşluklu görünmez. auto-fill ise sütun hizasının korunması gerektiğinde tercih edilir: farklı satırlardaki ögelerin aynı sütun hatlarında kalmasını istiyorsan ya da ızgaraya sonradan öge eklendiğinde düzenin kaymamasını istiyorsan. Not: bu kalıp, eskiden dört-beş medya sorgusu gerektiren duyarlı kart ızgarasını tek satıra indirir.

1fr ile tanımladığın bir sütun neden içeriğinden daha dar olmuyor?

Çünkü 1fr aslında minmax(auto, 1fr) anlamına gelir: izin en büyük boyutu bir paydır, ama en küçük boyutu auto'dur — yani içeriğinin en küçük boyutundan (kırılamayan en uzun kelime, geniş bir tablo, bir <pre> bloğu) daha dar olamaz. Sonuç: iki 1fr sütunlu bir ızgara, içine uzun bir URL konduğunda taşar ve sayfada yatay kaydırma çubuğu çıkar. Çözüm izi minmax(0, 1fr) olarak tanımlamaktır; alternatif olarak hücreye min-width: 0 ya da overflow: hidden yazmaktır. Bu, 9. derste Flexbox'ta gördüğün min-width: auto tuzağının Grid'deki tam karşılığıdır ve aynı belirtiyi verir. Kaydırılabilir bir bölgeyi hücreye koyduğunda da gereklidir — aksi hâlde bölge kaydırılmak yerine hücreyi büyütür. Metnin kendisi taşıyorsa ayrıca overflow-wrap: break-word eklenir.

grid-template-areas nedir, avantajı ve sınırları nelerdir?

Izgara alanlarına ad vererek yerleşimi CSS içinde bir harita gibi çizmeyi sağlar: "ustbar ustbar" "yanmenu icerik" yazdığında düzeni okurken görürsün. Ögeler grid-area: icerik ile yerlerine oturur. Avantajı okunabilirlik ve duyarlı düzendir: dar ekranda yalnızca haritayı değiştirerek tüm yerleşimi yeniden kurarsın, ne işaretlemeye ne öge kurallarına dokunursun. Kuralları: her alan dikdörtgen olmalıdır (L şeklinde alan tanımlanamaz), her satırda sütun sayısı eşit olmalıdır ve boş hücre için . yazılır. Sınırları: (1) çok sayıda ve dinamik öge için uygun değildir — orada otomatik yerleşim ya da auto-fit kullanılır; (2) alan adları CSS'te sabittir, bileşen içeriği değişkense esnek olmaz; (3) en önemlisi, görsel sırayı DOM sırasından koparabilir — dar ekranda yan menüyü içerikten sonraya almak gözle işe yarar ama klavye ve ekran okuyucu hâlâ DOM sırasını izler, dolayısıyla sırası anlamlı içerikte işaretlemeyi doğru yazmak gerekir.

10Sınav köşesi

Yazılıda nasıl sorulur

(1) CSS Grid nedir, Flexbox'tan farkı nedir? (2) grid-template-columns ve grid-template-rows nasıl tanımlanır? (3) fr birimi nedir? (4) repeat(), minmax(), auto-fit, auto-fill kullanımı. (5) grid-template-areas ile yerleşim kurunuz — genelde uygulamalı sorulur. (6) grid-column / grid-row ve span. (7) Grid hizalama özellikleri; justify-items ile justify-content farkı. (8) Örtük ve açık ızgara. (9) Medya sorgusu kullanmadan duyarlı ızgara nasıl yapılır? (10) Grid ile tablo arasındaki fark; hangisi ne zaman?

Sözlüde nasıl anlatılır — 2 dakikalık taslak

Düzen: (1) Tanım — "Grid iki boyutlu yerleşim sistemidir: satır ve sütunu birlikte tanımlar. Flexbox içerikten yerleşime çalışır, Grid yerleşimden içeriğe." (2) Temel araçlar — "izleri grid-template-columns ile tanımlarım; fr kalan boşluğun payıdır, minmax ile alt ve üst sınır koyarım." (3) Kıdem vuruşu — "repeat(auto-fit, minmax(260px, 1fr)) tek satırla duyarlı kart ızgarası verir; medya sorgusu yazmam. auto-fill boş izleri korur, auto-fit daraltır — fark yalnız öge sayısı sütun sayısından azken görünür." (4) Tuzak bilgisi — "1fr aslında minmax(auto, 1fr)'dir; içinde uzun bir URL olan sütun daralmaz ve ızgara taşar, bunun için minmax(0, 1fr) yazarım." (5) Pratik ve sınır — "sayfa iskeletini grid-template-areas ile kurarım, dar ekranda yalnız haritayı değiştiririm. Ama görsel sırayı DOM sırasından kopardığım yerde klavye ve ekran okuyucu eski sırayı izler; ayrıca Grid tabloyu anlamsal olarak değiştirmez — veri tablosu tablodur, Grid yalnız yerleşim tablosunu ortadan kaldırır."