Ders 04 / 23
Izgara Yerleşimi
Ögelerin hat numaralarıyla açık yerleştirilmesi, otomatik yerleştirme algoritmasının imleç kuralı, seyrek ve yoğun kiplerin farkı, örtük şeritlerin oluşumu ve görsel sıra ile belge sırasının ayrılması.
İçindekiler
Bir önceki ders ızgarayı kurdu ve alanları adlandırdı. Adlandırılmış alan yazımı yerleşimi okunur kılar ama her düzen için uygun değildir: sayıları önceden bilinmeyen ölçüm kartları tek tek adlandırılamaz.
Bu ders iki soruyu yanıtlar. Bir öge hatlara göre nasıl açıkça yerleştirilir, ve yerleşim bildirimi yazılmamış ögeler hangi kurala göre dağıtılır?
Hat Numaralarına Çözülme
Bir ögenin yerleşimi iki eksende dört hatla verilir: grid-column sütun hatlarını,
grid-row satır hatlarını bildirir. Her biri eğik çizgiyle ayrılmış başlangıç ve bitiş
alır.
// hat.mjs — grid-column yaziminin hat numaralarina cozulmesi const SUTUN = 4; // 4 serit -> 5 hat const SON_HAT = SUTUN + 1; // -1 ile anilan hat // eksi numarali hat sondan sayilir: -1 -> SON_HAT, -2 -> SON_HAT-1 const hat = (n) => (n > 0 ? n : SON_HAT + 1 + n); function coz(yazim) { const [bas, son] = yazim.split("/").map((p) => p.trim()); let basHat = hat(Number(bas)); let sonHat; if (son === undefined) sonHat = basHat + 1; // tek deger: bir serit else if (son.startsWith("span")) sonHat = basHat + Number(son.split(" ")[1]); else sonHat = hat(Number(son)); if (sonHat < basHat) [basHat, sonHat] = [sonHat, basHat]; // ters yazim duzeltilir return { basHat, sonHat, serit: sonHat - basHat }; } console.log(`${SUTUN} sutun serit -> hatlar 1..${SON_HAT} (ayni hatlar -${SON_HAT}..-1)`); for (const y of ["1 / 3", "2 / -1", "1 / span 2", "-3 / -1", "3", "4 / 2"]) { const { basHat, sonHat, serit } = coz(y); console.log(`grid-column: ${y.padEnd(12)} -> hat ${basHat} ile hat ${sonHat} arasi, ${serit} serit`); } console.log("\n--- eksi ve arti numaralarin esitligi ---"); for (let n = 1; n <= SON_HAT; n++) { console.log(`hat ${n} = hat ${n - SON_HAT - 1}`); }
4 sutun serit -> hatlar 1..5 (ayni hatlar -5..-1) grid-column: 1 / 3 -> hat 1 ile hat 3 arasi, 2 serit grid-column: 2 / -1 -> hat 2 ile hat 5 arasi, 3 serit grid-column: 1 / span 2 -> hat 1 ile hat 3 arasi, 2 serit grid-column: -3 / -1 -> hat 3 ile hat 5 arasi, 2 serit grid-column: 3 -> hat 3 ile hat 4 arasi, 1 serit grid-column: 4 / 2 -> hat 2 ile hat 4 arasi, 2 serit --- eksi ve arti numaralarin esitligi --- hat 1 = hat -5 hat 2 = hat -4 hat 3 = hat -3 hat 4 = hat -2 hat 5 = hat -1
Beş yazım biçimi ve tek bir kural: her bildirim iki hat numarasına çözülür, aradaki şerit sayısı farktır.
2 / -1 yazımı ikinci hattan son hatta uzanır. Şerit sayısı bildirimde yazılı değildir;
ızgara altı sütuna çıkarsa aynı bildirim beş şerit kaplar. Sondan numaralama, düzenin şerit
sayısından bağımsız yazılmasını sağlar.
span anahtar sözcüğü hat yerine uzunluk bildirir: 1 / span 2 başlangıçtan iki şerit
gider. Başlangıç hattı bilinmeyen bir ögede yalnızca span 2 yazmak da geçerlidir; o zaman
öge otomatik yerleştirilir ama iki şerit kaplar.
Son satır bir ayrıntıyı gösteriyor: bitiş hattı başlangıçtan küçükse ikisi yer değiştirir.
4 / 2 yazımı hata değildir, ikinci ve dördüncü hatlar arasına çözülür.
Dört bildirimin kısayolu grid-area özelliğidir ve sırası alışılmışın dışındadır:
satır başlangıcı, sütun başlangıcı, satır bitişi, sütun bitişi. Bir önceki derste
grid-area: kunye yazımıyla alan adı verilmişti; aynı özellik ad yerine dört hat da alır.
Otomatik Yerleştirme
Yerleşim bildirimi olmayan ögeler otomatik yerleştirme (auto-placement) algoritmasıyla dağıtılır. Algoritma bir imleç tutar, ögeleri belge sırasına göre gezer ve her ögeyi imleçten itibaren sığdığı ilk boşluğa koyar.
grid-auto-flow bildirimi hangi eksende ilerleneceğini söyler: row değeri satırı
doldurup alt satıra iner, column değeri sütunu doldurup yandaki sütuna geçer. Üçüncü bir
değer olan dense, imlecin geri gitmesine izin verir.
// yerlestirme.mjs — otomatik yerlestirme algoritmasinin seyrek ve yogun kipleri const SUTUN = 3; // yay = kac sutun serit kaplayacagi const ogeler = [ { ad: "sicaklik", yay: 1 }, { ad: "nem", yay: 2 }, { ad: "ruzgar", yay: 2 }, { ad: "basinc", yay: 1 }, { ad: "yagis", yay: 1 }, { ad: "kar", yay: 3 }, { ad: "gunes", yay: 1 }, { ad: "toprak", yay: 2 }, ]; function yerlestir(yogun) { const dolu = []; // dolu[satir][sutun] = oge adi const yer = () => { dolu.push(new Array(SUTUN).fill(null)); }; const uygun = (s, c, yay) => { if (c + yay > SUTUN) return false; while (dolu.length <= s) yer(); for (let i = 0; i < yay; i++) if (dolu[s][c + i]) return false; return true; }; const sonuc = []; let imlecSatir = 0, imlecSutun = 0; for (const o of ogeler) { let s = yogun ? 0 : imlecSatir; let c = yogun ? 0 : imlecSutun; while (!uygun(s, c, o.yay)) { c += 1; if (c + o.yay > SUTUN) { c = 0; s += 1; } } while (dolu.length <= s) yer(); for (let i = 0; i < o.yay; i++) dolu[s][c + i] = o.ad; sonuc.push({ ad: o.ad, satir: s + 1, sutun: c + 1, yay: o.yay }); if (!yogun) { // seyrek kipte imlec geri gitmez imlecSatir = s; imlecSutun = c + o.yay; if (imlecSutun >= SUTUN) { imlecSatir = s + 1; imlecSutun = 0; } } } return { dolu, sonuc }; } function yaz(baslik, { dolu, sonuc }) { console.log(`\n=== ${baslik} ===`); for (const y of sonuc) { console.log(` ${y.ad.padEnd(9)} satir ${y.satir}, sutun ${y.sutun}..${y.sutun + y.yay - 1} (grid-column: ${y.sutun} / span ${y.yay})`); } console.log(` satir sayisi: ${dolu.length}`); const bosHucre = dolu.flat().filter((h) => h === null).length; console.log(` bos hucre: ${bosHucre}`); for (const satir of dolu) { console.log(" | " + satir.map((h) => (h ?? "-").padEnd(9)).join(" | ") + " |"); } } console.log(`${SUTUN} sutunluk izgara, ${ogeler.length} oge, yaylar: ${ogeler.map((o) => o.yay).join(" ")}`); yaz("grid-auto-flow: row (seyrek, varsayilan)", yerlestir(false)); yaz("grid-auto-flow: row dense (yogun)", yerlestir(true));
3 sutunluk izgara, 8 oge, yaylar: 1 2 2 1 1 3 1 2 === grid-auto-flow: row (seyrek, varsayilan) === sicaklik satir 1, sutun 1..1 (grid-column: 1 / span 1) nem satir 1, sutun 2..3 (grid-column: 2 / span 2) ruzgar satir 2, sutun 1..2 (grid-column: 1 / span 2) basinc satir 2, sutun 3..3 (grid-column: 3 / span 1) yagis satir 3, sutun 1..1 (grid-column: 1 / span 1) kar satir 4, sutun 1..3 (grid-column: 1 / span 3) gunes satir 5, sutun 1..1 (grid-column: 1 / span 1) toprak satir 5, sutun 2..3 (grid-column: 2 / span 2) satir sayisi: 5 bos hucre: 2 | sicaklik | nem | nem | | ruzgar | ruzgar | basinc | | yagis | - | - | | kar | kar | kar | | gunes | toprak | toprak | === grid-auto-flow: row dense (yogun) === sicaklik satir 1, sutun 1..1 (grid-column: 1 / span 1) nem satir 1, sutun 2..3 (grid-column: 2 / span 2) ruzgar satir 2, sutun 1..2 (grid-column: 1 / span 2) basinc satir 2, sutun 3..3 (grid-column: 3 / span 1) yagis satir 3, sutun 1..1 (grid-column: 1 / span 1) kar satir 4, sutun 1..3 (grid-column: 1 / span 3) gunes satir 3, sutun 2..2 (grid-column: 2 / span 1) toprak satir 5, sutun 1..2 (grid-column: 1 / span 2) satir sayisi: 5 bos hucre: 2 | sicaklik | nem | nem | | ruzgar | ruzgar | basinc | | yagis | gunes | - | | kar | kar | kar | | toprak | toprak | - |
İki harita aynı sekiz ögeyi aynı üç sütuna yerleştiriyor ve ilk altı öge için sonuç aynı. Ayrım yedinci ögede başlar.
Seyrek kipte imleç, kar ögesi dördüncü satırı kapladıktan sonra beşinci satıra geçmiştir
ve geri gitmez. Üçüncü satırda iki hücre boş olmasına rağmen gunes ögesi beşinci
satıra iner. Boşluğun kalması bir kusur değil, kuralın sonucudur: belge sırası ile görsel
sıra arasındaki bağı korur.
Yoğun kipte her öge için arama ızgaranın başından yapılır. gunes üçüncü satırdaki boşluğa
yerleşir. toprak ögesi iki şerit istediği için oraya sığmaz ve beşinci satıra iner —
yoğun kip boşlukları doldurur, ama sığmayan ögeyi zorlamaz.
Sonuçta iki kipte de iki hücre boş kalır; değişen, hangi ögenin nerede olduğudur. Yoğun kip her zaman daha az boşluk bırakmaz, yalnızca daha erken doldurur.
Yoğun Kipin Bedeli
Yoğun kipte gunes ögesi, belgede kendisinden sonra gelen kar ögesinden yukarıda
görünür. Görsel sıra ile belge sırası ayrışmıştır.
Bunun somut sonuçları vardır. Klavyeyle gezinen bir kullanıcı sekme tuşuna bastığında odak belge sırasını izler ve ekranda yukarı geri sıçrar. Ekran okuyucu belge sırasını okur ve görsel düzenle uyuşmaz. İki kullanıcı aynı sayfayı iki farklı sırada algılar.
Aynı uyarı order bildirimi, flex-direction: row-reverse ve açık hat yerleştirmesiyle
oluşturulan her sıra değişikliği için geçerlidir. Kural şudur: görsel sıra ile belge sırası
ayrılıyorsa, belgedeki sıranın okuma sırası olarak doğru olduğundan emin olunmalıdır;
görsel düzen bu sıranın üzerine kurulur, onun yerine geçmez.
Ölçüm kartları için karar kolaydır: kartların sırası ölçüm türünün önemini bildirmiyorsa yoğun kip kullanılabilir. Sıra anlam taşıyorsa — örneğin ölçümler zaman sırasındaysa — seyrek kip korunur.
Örtük Şeritler
Şerit tanımı ızgarayı sınırlar ama ögeleri sınırlamaz. Sekiz ögenin yerleşmesi için beş satır gerekti; oysa şerit tanımında satır sayısı yazılı değildi. Tanımlanandan fazla öge olduğunda ızgara kendiliğinden büyür ve oluşan şeritlere örtük şerit (implicit track) denir.
Tanımlı olanlar açık ızgarayı (explicit grid), kendiliğinden oluşanlar örtük ızgarayı
(implicit grid) kurar. Ayrımın iki sonucu vardır. Birincisi, örtük şeritlerin ölçüsü
grid-template-* bildiriminden değil grid-auto-rows ve grid-auto-columns
bildirimlerinden gelir; yazılmazsa ölçü içeriktir. İkincisi, sondan numaralama () yalnız
açık ızgarada tanımlıdır; örtük şeritler bu numaralamaya katılmaz.
/* duzen.css — 4. adım: ölçüm kartları */ .olcum-kartlari { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); grid-auto-rows: minmax(8rem, auto); gap: var(--aralik-0); } .olcum-kartlari .genis { grid-column: span 2; } .olcum-kartlari .ozet { grid-column: 1 / -1; grid-row: 1; }
grid-auto-rows: minmax(8rem, auto) bildirimi her örtük satıra bir alt sınır verir: kısa
içerikli kartlar da en az sekiz taban birim yüksekliğinde olur, uzun içerikli kartlar
büyüyebilir. 1 / -1 yazımı özet kartını satırın tamamına yayar ve şerit sayısı ekran
genişliğiyle değiştiğinde de doğru kalır.
Bir uyarı: span 2 yazan bir kart, auto-fill tek şerit ürettiğinde iki şerit isteyecektir.
Bu durumda öge açık ızgaranın dışına taşmaz; ızgara sağa doğru bir örtük sütun ekler ve
düzen bozulur. Kartlara span verilecekse şerit sayısının en az iki olduğu genişlikler
ayrıca sınırlanmalıdır — bu koşullu yazımın aracı sonraki konudaki sorgulardır.
Hizalama İki Düzeyde Çalışır
Izgarada hizalama iki ayrı soruya yanıt verir. Birincisi: bir öge kendi alanının içinde
nereye oturur? justify-self satır içi eksende, align-self blok eksende bunu bildirir;
kapsayıcıda yazılan justify-items ve align-items bütün ögeler için varsayılanı verir.
Varsayılan değer stretch olduğu için öge alanını doldurur.
İkincisi: şeritlerin toplamı kapsayıcıdan küçükse ızgaranın kendisi nereye oturur?
justify-content ve align-content bunu bildirir ve değer kümesi esnek kutudakiyle
aynıdır. Şeritler fr ile tanımlıysa boş alan kalmadığı için bu bildirimlerin etkisi
görünmez; sabit ölçülü şeritlerde görünür.
Esnek kutuda justify-content ögeleri dağıtıyordu; ızgarada şeritleri dağıtır. Aynı ad, iki
modelde farklı nesneye uygulanır ve bu ayrım karıştırıldığında bildirim etkisiz görünür.
Özet
- Her yerleşim bildirimi iki hat numarasına çözülür;
spanuzunluk bildirir, eksi numaralar sondan sayılır ve ters yazılan hatlar yer değiştirir. - Otomatik yerleştirme, ögeleri belge sırasına göre imleçten itibaren sığdıkları ilk boşluğa koyar; seyrek kipte imleç geri gitmez ve boşluklar kalır.
- Yoğun kip boşlukları doldurur ama görsel sırayı belge sırasından ayırır; odak sırası ve ekran okuyucu belge sırasını izlemeye devam eder.
- Tanımlıdan fazla öge, ölçüsü
grid-auto-rowsvegrid-auto-columnsbildirimlerinden gelen örtük şeritler üretir; sondan numaralama örtük şeritleri kapsamaz. - Izgarada
justify-itemsvealign-itemsögeyi alanının içine,justify-contentvealign-contentşeritleri kapsayıcının içine yerleştirir.
Sonraki Adım
İki düzen modeli de kurulmuş oldu: biri tek eksende dağıtır, diğeri iki eksende hat tanımlar. Aynı düzenin her ikisiyle de kurulabildiği durumlar vardır ve seçim çoğu zaman alışkanlıkla yapılır. Sonraki ders bu seçimi ölçüte bağlar: hangi soru hangi modelle daha az bildirimle ve daha az kırılganlıkla yanıtlanır?
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.