Ders 03 / 23
Izgara Modeli
Izgara bağlamının kurulması, şerit ile hat ayrımı, pay biriminin boş alanı bölmesi, en küçük içerik ölçüsünün pay üzerindeki gizli alt sınırı ve alanların adlandırılması.
İçindekiler
Esnek kutu tek eksende dağıtır: bir doğrultuda paylaştırır, diğerinde yalnızca hizalar. Bir süzgeç çubuğu için bu yeterlidir. Ölçüm sayfasının bütünü ise iki eksende hizalanmış bölgeler ister: künye, ölçüm çizelgesi ve yan sütun birbirinin hem satırına hem sütununa göre yerleşmelidir.
Bu ders, satır ve sütunları önceden tanımlayan düzen modelini kurar. Esnek kutuda yerleşim ögelerin ölçülerinden doğar; ızgarada önce boş bir çizgi düzeni tanımlanır ve ögeler bu düzene yerleştirilir.
Izgara Bağlamı
Bir kutuya display: grid bildirildiğinde kutu ızgara kapsayıcısı (grid container)
olur; doğrudan çocukları ızgara ögesi (grid item) olarak yerleştirilir. Esnek kutudaki
gibi kapsayıcının kendisi akışta blok kutu olarak kalır, çocukların display değeri
bloklaşır ve dış boşlukları çökmez.
Ayrım, kapsayıcıya ne bildirildiğindedir. Esnek kutuda tek bir yön bildirilir; ızgarada iki eksenin şerit tanımı yazılır:
.istasyon-duzeni { display: grid; grid-template-columns: 240px 2fr 1fr; grid-template-rows: auto 1fr; gap: 24px; }
Şerit, Hat ve Hücre
Dört kavram birbirinden ayrı tutulur.
Şerit (grid track) iki komşu çizgi arasındaki bant: bir sütun ya da bir satır. Yukarıdaki bildirim üç sütun şeridi ve iki satır şeridi tanımlar.
Hat (grid line) şeritleri ayıran çizgi. Üç sütun şeridi dört hat üretir; hatlar başlangıçtan itibaren 1’den numaralanır. Aynı hatlar sondan başlayarak eksi değerlerle de anılır: son hat , bir öncesi . Bir ögeyi ızgaranın sonuna kadar uzatmak için şerit sayısını bilmek gerekmez, yeterlidir.
Hücre (grid cell) bir satır şeridi ile bir sütun şeridinin kesişimi; ızgaranın en küçük birimi.
Alan (grid area) dört hatla sınırlanan dikdörtgen bölge; bir ya da daha çok hücreyi kapsar. Bir ögenin yerleşimi her zaman bir alandır.
Hatlara ad verilebilir ve ad, köşeli ayraç içinde şerit tanımının arasına yazılır:
.istasyon-duzeni { display: grid; grid-template-columns: [kenar-bas] 240px [icerik-bas] 2fr 1fr [kenar-son]; }
Adlandırılmış hat, sayı yerine kullanılabilir ve şerit sayısı değiştiğinde yerleşim bildirimlerinin yeniden yazılmasını gereksiz kılar.
Pay Birimi Boş Alanı Böler
fr, ızgaraya özgü bir birimdir: pay birimi (fractional unit). Bir uzunluk değildir;
sabit şeritler ve aralıklar düşüldükten sonra kalan alanın kaç paya bölüneceğini söyler.
// serit.mjs — fr biriminin bos alani boluse ve gizli alt siniri const ARALIK = 24; // serit tanimi: sabit uzunluklar once ayrilir, kalan fr paylarina bolunur const seritler = [ { yazim: "240px", sabit: 240, fr: 0 }, { yazim: "2fr", sabit: 0, fr: 2 }, { yazim: "1fr", sabit: 0, fr: 1 }, ]; const araToplam = ARALIK * (seritler.length - 1); const sabitToplam = seritler.reduce((t, s) => t + s.sabit, 0); const frToplam = seritler.reduce((t, s) => t + s.fr, 0); function paylar(kapsayici) { const bos = kapsayici - sabitToplam - araToplam; return seritler.map((s) => s.sabit + (s.fr / frToplam) * bos); } const KAP = 960; console.log(`grid-template-columns: ${seritler.map((s) => s.yazim).join(" ")} gap: ${ARALIK}px kapsayici: ${KAP}px`); console.log(`sabit=${sabitToplam} aralik=${araToplam} bolunecek bos alan=${KAP - sabitToplam - araToplam} fr toplami=${frToplam}`); paylar(KAP).forEach((o, i) => console.log(` ${seritler[i].yazim.padEnd(6)} -> ${o.toFixed(1)}px`)); console.log("\n--- fr, kapsayicinin degil bos alanin payidir ---"); for (const ekSabit of [0, 240, 480]) { const bir = (KAP - ekSabit - araToplam) / 3; console.log(`sabit serit ${String(ekSabit).padStart(3)}px -> 1fr = ${bir.toFixed(1)}px (2fr = ${(2 * bir).toFixed(1)}px)`); } // dar kapsayicida fr payi, seridin en kucuk icerik olcusunun altina duser const DAR = 600; const enKucukIcerik = [90, 180, 160]; // her seridin en uzun bolunemez icerigi console.log(`\n--- dar kapsayici (${DAR}px): 1fr = minmax(auto, 1fr) ---`); let toplam = 0; paylar(DAR).forEach((pay, i) => { const alt = seritler[i].fr > 0 ? enKucukIcerik[i] : 0; const uygulanan = Math.max(pay, alt); toplam += uygulanan; console.log(` ${seritler[i].yazim.padEnd(6)} pay=${pay.toFixed(1).padStart(6)} en kucuk icerik=${String(alt).padStart(3)} uygulanan=${uygulanan.toFixed(1).padStart(6)}`); }); console.log(` seritler+aralik = ${(toplam + araToplam).toFixed(1)}px, kapsayici = ${DAR}px, tasma = ${(toplam + araToplam - DAR).toFixed(1)}px`); console.log(`\n--- ayni kapsayicida minmax(0, 1fr) ---`); let toplam2 = 0; paylar(DAR).forEach((pay, i) => { toplam2 += pay; const ad = seritler[i].fr > 0 ? `minmax(0, ${seritler[i].fr}fr)` : seritler[i].yazim; console.log(` ${ad.padEnd(16)} uygulanan=${pay.toFixed(1).padStart(6)}`); }); console.log(` seritler+aralik = ${(toplam2 + araToplam).toFixed(1)}px, tasma = ${(toplam2 + araToplam - DAR).toFixed(1)}px`);
grid-template-columns: 240px 2fr 1fr gap: 24px kapsayici: 960px sabit=240 aralik=48 bolunecek bos alan=672 fr toplami=3 240px -> 240.0px 2fr -> 448.0px 1fr -> 224.0px --- fr, kapsayicinin degil bos alanin payidir --- sabit serit 0px -> 1fr = 304.0px (2fr = 608.0px) sabit serit 240px -> 1fr = 224.0px (2fr = 448.0px) sabit serit 480px -> 1fr = 144.0px (2fr = 288.0px) --- dar kapsayici (600px): 1fr = minmax(auto, 1fr) --- 240px pay= 240.0 en kucuk icerik= 0 uygulanan= 240.0 2fr pay= 208.0 en kucuk icerik=180 uygulanan= 208.0 1fr pay= 104.0 en kucuk icerik=160 uygulanan= 160.0 seritler+aralik = 656.0px, kapsayici = 600px, tasma = 56.0px --- ayni kapsayicida minmax(0, 1fr) --- 240px uygulanan= 240.0 minmax(0, 2fr) uygulanan= 208.0 minmax(0, 1fr) uygulanan= 104.0 seritler+aralik = 600.0px, tasma = 0.0px
İlk blok hesabın sırasını gösteriyor: 960 birimlik kapsayıcıdan önce sabit şerit (240) ve
iki aralık (48) düşülür, kalan 672 birim üç paya bölünür. 2fr iki pay alır (448), 1fr
bir pay (224).
İkinci blok sık yapılan bir okuma hatasını düzeltiyor. 1fr kapsayıcının üçte biri
değildir; boş alanın üçte biridir. Sabit şerit büyüdükçe aynı 1fr bildiriminin
karşılığı 304’ten 144’e iner. Şerit tanımının kendisi değişmemiştir, bölünen değişmiştir.
Pay toplamı birden küçükse boş alanın tamamı dağıtılmaz: 0.5fr 0.5fr yazımı boş alanın
yarısını kullanır, kalanı ızgaranın sonunda durur. Bu davranış, aynı bildirimin esnek
kutudaki karşılığıyla tutarlıdır.
Payın Gizli Alt Sınırı
Üçüncü blok, ızgara tanımlarındaki en sık taşma nedenini gösteriyor. Kapsayıcı 600 birime indiğinde son şeridin payı 104 birim hesaplanır, ama şeridin içinde bölünemeyen 160 birimlik bir içerik vardır — uzun bir ölçüm kodu ya da bir tablo. Şerit 160’ta durur ve toplam kapsayıcıyı 56 birim aşar.
Nedeni şudur: 1fr yazımı, tam açılımıyla minmax(auto, 1fr) demektir. Alt sınır auto
olduğunda şerit, içeriğinin en küçük içerik ölçüsünün altına inemez. Pay bu sınırın
altına düşerse sınır kazanır.
Dördüncü blok çözümü veriyor: alt sınır açıkça sıfıra çekilirse şerit paya uyar ve taşma ortadan kalkar. Bedeli, içeriğin şerit içinde taşabilmesidir; taşma yönetimi CSS ile Görsel Sunum kursunda kurulan bildirimlerle o şeritte ayrıca ele alınır.
Bu, esnek kutudaki min-width: auto kısıtının ızgaradaki karşılığıdır. İki modelde de
sorunun kaynağı aynıdır: içerik ölçüsü, hesaplanan paydan büyük olduğunda kısıt kazanır.
Yineleme ve Aralık
Aynı şerit tanımını elle tekrarlamak yerine repeat() yazılır. İlginç olan, yineleme
sayısının bir sayı yerine iki anahtar sözcükle verilebilmesidir: auto-fill ve auto-fit.
İkisi de kapsayıcıya sığan en çok şeridi üretir; ayrım, üretilen şeritlerin boş kalması
durumundadır.
// yineleme.mjs — auto-fill ve auto-fit ile uretilen serit sayisi const EN_KUCUK = 220; // minmax(220px, 1fr) const ARALIK = 24; const OGE_SAYISI = 5; // kapsayiciya sigan en cok serit: n*enKucuk + (n-1)*aralik <= genislik function seritSayisi(genislik) { const n = Math.floor((genislik + ARALIK) / (EN_KUCUK + ARALIK)); return Math.max(1, n); } const olcu = (genislik, n) => (genislik - ARALIK * (n - 1)) / n; console.log("repeat(auto-fill | auto-fit, minmax(220px, 1fr)) gap: 24px oge sayisi: 5"); console.log("genislik serit auto-fill olcu dolu serit auto-fit olcu"); for (const g of [320, 500, 760, 1000, 1240, 1600]) { const n = seritSayisi(g); const dolu = Math.min(n, OGE_SAYISI); const fill = olcu(g, n); const fit = olcu(g, dolu); console.log( String(g).padStart(8) + String(n).padStart(7) + (fill.toFixed(1) + "px").padStart(16) + String(dolu).padStart(12) + (fit.toFixed(1) + "px").padStart(15) ); } console.log("\n--- sinir: serit sayisinin arttigi tam genislikler ---"); for (let n = 1; n <= 6; n++) { const esik = n * EN_KUCUK + (n - 1) * ARALIK; console.log(`${n} serit icin gereken en az genislik: ${esik}px`); } console.log("\n--- ayni hesap sabit serit sayisiyla: repeat(4, minmax(220px, 1fr)) ---"); for (const g of [500, 760, 1000]) { const n = 4; const pay = olcu(g, n); const uygulanan = Math.max(pay, EN_KUCUK); const tasma = uygulanan * n + ARALIK * (n - 1) - g; console.log(`genislik ${String(g).padStart(4)} -> pay ${pay.toFixed(1)}px, uygulanan ${uygulanan.toFixed(1)}px, tasma ${tasma.toFixed(1)}px`); }
repeat(auto-fill | auto-fit, minmax(220px, 1fr)) gap: 24px oge sayisi: 5
genislik serit auto-fill olcu dolu serit auto-fit olcu
320 1 320.0px 1 320.0px
500 2 238.0px 2 238.0px
760 3 237.3px 3 237.3px
1000 4 232.0px 4 232.0px
1240 5 228.8px 5 228.8px
1600 6 246.7px 5 300.8px
--- sinir: serit sayisinin arttigi tam genislikler ---
1 serit icin gereken en az genislik: 220px
2 serit icin gereken en az genislik: 464px
3 serit icin gereken en az genislik: 708px
4 serit icin gereken en az genislik: 952px
5 serit icin gereken en az genislik: 1196px
6 serit icin gereken en az genislik: 1440px
--- ayni hesap sabit serit sayisiyla: repeat(4, minmax(220px, 1fr)) ---
genislik 500 -> pay 107.0px, uygulanan 220.0px, tasma 452.0px
genislik 760 -> pay 172.0px, uygulanan 220.0px, tasma 192.0px
genislik 1000 -> pay 232.0px, uygulanan 232.0px, tasma 0.0px
minmax(a, b) bir şeridin alt ve üst sınırını verir: şerit a değerinin altına inmez, b
değerinin üstüne çıkmaz. minmax(220px, 1fr) yazımı “en az 220 birim, kalanı pay olarak
al” demektir ve yineleme sayısı bu alt sınırdan türetilir.
Şerit sayısı doğrudan çıkar: şerit için gereken en az genişlik birimdir ve kapsayıcı bu değeri aştıkça sayı artar. İkinci blok bu eşikleri veriyor; birinci bloktaki sayılar tam olarak eşiklerle uyumludur — 1000 birimlik kapsayıcı dört şerit alır, çünkü dördüncü eşik 952’dir ve beşinci eşik 1196’dır.
Ayrım son satırda görünür. 1600 birimlik kapsayıcı altı şerit alacak kadar geniştir ama
yerleştirilecek beş öge vardır. auto-fill altıncı şeridi boş olarak korur; ögeler 246,7
birimde kalır ve sağda boş bir sütun durur. auto-fit boş şeridi çökertir; şerit ve
aralığı ortadan kalkar, beş öge kalan alanı paylaşır ve 300,8 birime çıkar.
Seçim ölçütü içerikle ilgilidir. Kart genişliğinin tutarlı kalması isteniyorsa ve ögeler
farklı sayfalarda değişiyorsa auto-fill doğrudur: aynı kart her sayfada aynı genişliktedir.
Ögelerin kapsayıcıyı her durumda doldurması isteniyorsa auto-fit doğrudur.
Üçüncü blok, sabit yineleme sayısının neden dar ekranlarda taştığını gösteriyor:
repeat(4, …) yazımı dört şeridi koşulsuz üretir, alt sınır 220 birimde tutar ve 500
birimlik bir kapsayıcıda 452 birim taşma verir. Yineleme anahtar sözcükleri bu koşulu
kapsayıcıdan okur; bir sonraki konuda ele alınacak ortam sorgularına gerek kalmadan şerit
sayısını uyarlarlar.
Alanların Adlandırılması
Şerit tanımı ızgarayı kurar; ögelerin nereye düşeceği ayrı bir bildirimdir. En okunur yolu, alanlara ad vermek ve yerleşimi kapsayıcıda metin olarak çizmektir:
/* duzen.css — 3. adım: sayfa ızgarası */ .istasyon-duzeni { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); grid-template-rows: auto auto 1fr; grid-template-areas: "kunye kunye" "olcumler yan-bilgi" "konum yan-bilgi"; gap: var(--aralik-1); } .kunye { grid-area: kunye; } .olcum-bolumu { grid-area: olcumler; } .konum-bolumu { grid-area: konum; } .yan-bilgi { grid-area: yan-bilgi; }
Dizgilerin her satırı bir satır şeridine, her sütunu bir sütun şeridine karşılık gelir. Aynı
adın iki hücrede geçmesi, alanın o hücreleri kapsadığını söyler; yan-bilgi iki satır
boyunca uzanır. Ad yerine nokta yazılırsa hücre boş bırakılır.
Bu yazımın değeri, düzenin biçem dosyasında görünür olmasıdır: satırların hizası ızgaranın kendisini çizer. Ögelerin belgedeki sırası ile ızgaradaki yeri birbirinden bağımsızdır — bu ayrımın erişilebilirlik sonuçları sonraki derste ele alınacaktır.
Özet
display: gridiki eksende şerit tanımı alır; şerit iki hat arasındaki bant, hücre iki şeridin kesişimi, alan ise dört hatla sınırlanan dikdörtgen bölgedir.- Hatlar baştan 1’den, sondan ’den numaralanır; ada bağlanabilir ve ad, şerit sayısı değiştiğinde yerleşim bildirimlerini korur.
frbir uzunluk değil pay birimidir: sabit şeritler ve aralıklar düşüldükten sonra kalan alanı böler, dolayısıyla kapsayıcının değil boş alanın oranını verir.1fraçılımıylaminmax(auto, 1fr)olduğu için şerit en küçük içerik ölçüsünün altına inmez; taşmayı önlemek için alt sınırminmax(0, 1fr)ile açıkça sıfırlanır.repeat(auto-fill, …)sığan bütün şeritleri üretir ve boş olanları korur,auto-fitboş şeritleri çökerterek kalan ögelere dağıtır.
Sonraki Adım
Şerit tanımı ızgarayı kurdu, adlandırılmış alanlar da yerleşimi çizdi. Ama alan tanımı yazılmamış ögeler nereye düşer? Kapsayıcının içinde tanımlanandan çok öge varsa ne olur? Sonraki ders, ögeleri hatlara göre açıkça yerleştiren bildirimleri ve boşta kalanları yerleştiren otomatik algoritmayı ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.