İçeriğe geç
academia.sh

Ders 05 / 23

Izgara ve Esnek Kutu Seçimi

İki düzen modelinin hangi soruyu yanıtladığı, son satır davranışının hesapla gösterilen farkı, yayılma isteğinin esnek kutuda doğurduğu maliyet ve iki modelin iç içe kullanımı.

İçindekiler

Önceki dört ders iki düzen modelini ayrı ayrı kurdu. Esnek kutu tek eksende dağıtıyor, ızgara iki eksende hat tanımlıyor. İkisiyle de bir kart dizisi yan yana dizilebilir, ikisiyle de bir gezinme çubuğu kurulabilir; seçim çoğu zaman en son öğrenilen modele göre yapılır.

Bu ders seçimi alışkanlıktan çıkarıp ölçüte bağlar. Ölçüt tek bir sorudur: düzen kararını içerik mi veriyor, yoksa siz mi veriyorsunuz? Sorunun yanıtı iki modelin adında değil, hesaplarının çıktığı yerde saklıdır.

Ölçünün Nereden Geldiği

Esnek kutuda hesap ögeden başlar. Her ögenin bir temel boyu vardır; bu boylar toplanır, kapsayıcıyla farkı alınır ve kalan alan büyüme ile daralma çarpanlarına göre bölüştürülür. Kapsayıcı ögelerin ne istediğini sorar, sonra pazarlık yapar. Bu yüzden esnek kutuya içerikten düzene çalışan model denir.

Izgarada hesap kapsayıcıdan başlar. Şerit tanımı, hiçbir öge yerleştirilmeden önce hatları belirler; ögeler sonra bu hatlara oturur. Şerit ölçüsü içerikten türetilebilir (auto, min-content, max-content) ama bu bir seçenektir, kuralın kendisi değildir. Izgara düzenden içeriğe çalışır.

Ayrım, iki modelin hangi soruya iyi yanıt verdiğini belirler:

  • Ögelerin sayısı ve ölçüsü önceden bilinmiyorsa, kalan alanı onlar arasında paylaştırmak gerekiyorsa — soru tek eksenlidir ve esnek kutu daha az bildirimle çözer.
  • Ögelerin birbirine göre hem satırda hem sütunda hizalanması gerekiyorsa, bir ögenin kapladığı alan diğerinin yerini belirliyorsa — soru iki eksenlidir ve ızgara gerekir.

“Tek eksenli” ifadesi ögelerin tek satırda kaldığı anlamına gelmez. flex-wrap: wrap bildirilmiş bir esnek kapsayıcı da birden çok satır üretir. Ayrım şudur: esnek kutuda her satır kendi içinde hesaplanır, satırlar birbirini görmez. Izgarada bütün satırlar aynı hat kümesini paylaşır.

Son Satırın Davranışı

Bu ayrımın en somut sonucu, ögeler tam bölünmediğinde ortaya çıkar. Aşağıdaki program aynı yedi kartı aynı kapsayıcıda iki modelle yerleştirir.

// secim.mjs — ayni kart dizisinin esnek kutu ve izgarayla yerlesimi
const KAPSAYICI = 980;   // px
const ARALIK = 16;       // gap
const TABAN = 200;       // flex-basis / minmax alt siniri
const OGE = 7;

// iki modelde de bir satira sigan oge sayisi ayni kuralla bulunur
const sigan = Math.max(1, Math.floor((KAPSAYICI + ARALIK) / (TABAN + ARALIK)));

// izgara: repeat(auto-fill, minmax(200px, 1fr)) -> her serit ayni olcu
const seritOlcu = (KAPSAYICI - ARALIK * (sigan - 1)) / sigan;

// esnek kutu: flex: 1 1 200px + flex-wrap: wrap -> her satir kendi icinde paylasir
function esnekSatirlar() {
  const satirlar = [];
  for (let i = 0; i < OGE; i += sigan) {
    const adet = Math.min(sigan, OGE - i);
    satirlar.push({ adet, olcu: (KAPSAYICI - ARALIK * (adet - 1)) / adet });
  }
  return satirlar;
}

const yaz = (v) => v.toFixed(1).padStart(6);

console.log(`kapsayici=${KAPSAYICI}px  gap=${ARALIK}px  taban=${TABAN}px  oge=${OGE}`);
console.log(`bir satira sigan oge: ${sigan}\n`);

console.log("--- izgara: repeat(auto-fill, minmax(200px, 1fr)) ---");
let no = 1;
for (let s = 0; s < Math.ceil(OGE / sigan); s++) {
  const adet = Math.min(sigan, OGE - s * sigan);
  let x = 0;
  const yerler = [];
  for (let i = 0; i < adet; i++) {
    yerler.push(`k${no++} ${yaz(x)}..${yaz(x + seritOlcu)}`);
    x += seritOlcu + ARALIK;
  }
  console.log(`satir ${s + 1}: ` + yerler.join("  "));
}

console.log("\n--- esnek kutu: flex: 1 1 200px; flex-wrap: wrap ---");
no = 1;
esnekSatirlar().forEach((satir, s) => {
  let x = 0;
  const yerler = [];
  for (let i = 0; i < satir.adet; i++) {
    yerler.push(`k${no++} ${yaz(x)}..${yaz(x + satir.olcu)}`);
    x += satir.olcu + ARALIK;
  }
  console.log(`satir ${s + 1}: ` + yerler.join("  "));
});

console.log("\n--- ilk sutunun sag kenari satirdan satira ---");
const ilkIzgara = seritOlcu;
esnekSatirlar().forEach((satir, s) => {
  const fark = satir.olcu - ilkIzgara;
  console.log(
    `satir ${s + 1}: izgara ${yaz(ilkIzgara)}  esnek ${yaz(satir.olcu)}  fark ${yaz(fark)}`,
  );
});
kapsayici=980px  gap=16px  taban=200px  oge=7
bir satira sigan oge: 4

--- izgara: repeat(auto-fill, minmax(200px, 1fr)) ---
satir 1: k1    0.0.. 233.0  k2  249.0.. 482.0  k3  498.0.. 731.0  k4  747.0.. 980.0
satir 2: k5    0.0.. 233.0  k6  249.0.. 482.0  k7  498.0.. 731.0

--- esnek kutu: flex: 1 1 200px; flex-wrap: wrap ---
satir 1: k1    0.0.. 233.0  k2  249.0.. 482.0  k3  498.0.. 731.0  k4  747.0.. 980.0
satir 2: k5    0.0.. 316.0  k6  332.0.. 648.0  k7  664.0.. 980.0

--- ilk sutunun sag kenari satirdan satira ---
satir 1: izgara  233.0  esnek  233.0  fark    0.0
satir 2: izgara  233.0  esnek  316.0  fark   83.0

İlk satırlar birebir aynı. İki model de kapsayıcıya dört kartın sığdığını aynı aritmetikle buluyor ve dört kartı aynı yerlere koyuyor. Ayrım ikinci satırda başlıyor.

Izgarada ikinci satır aynı hatları kullanır. Üç kart kalmıştır ama şeritler dörttür; kartlar ilk üç şeride oturur, dördüncü şerit boş kalır. Kartların ölçüsü değişmez: 233 birim.

Esnek kutuda ikinci satır kendi hesabını yapar. Üç kart 980 birimi paylaşır ve her biri 316 birime çıkar. Son satır 83 birim daha geniş kartlarla dolar; birinci satırın kart kenarları ile ikinci satırınkiler hiçbir noktada çakışmaz.

Bu bir kusur değil, iki modelin tanımının sonucudur. Hangisinin doğru olduğu ne istendiğine bağlıdır. Kartlar bir çizelgenin görsel karşılığıysa ve sütun hizası okumayı taşıyorsa ızgara doğrudur. Kartlar birbirinden bağımsız etiketlerse ve boş yer bırakmak istenmiyorsa esnek kutunun davranışı istenen davranıştır.

Sık görülen bir düzeltme girişimi, son satıra “hayalet” ögeler eklemektir: sığmayan boşluğu doldurmak için görünmez kutular. Bu, esnek kutuya ızgara işi yaptırmanın belirtisidir; belgeye anlamı olmayan öge eklemek yerine model değiştirmek daha ucuzdur.

Yayılma İsteğinin Bedeli

İkinci ölçüt, bir ögenin diğerlerinden daha geniş olması istendiğinde ortaya çıkar. Izgara bunu tek bildirimle yazar: grid-column: span 2. Esnek kutuda karşılığı bir orandır ve o oran şerit sayısına bağlıdır.

// yayilma.mjs — iki serit genisligindeki bir kartin iki modeldeki bedeli
const ARALIK = 16;
const TABAN = 200;

console.log("minmax(200px, 1fr), gap 16px — iki serit kaplayan kartin olcusu");
console.log("kapsayici  serit  serit olcu  span 2 olcu  ayni sonuc icin flex-basis");

for (const W of [640, 780, 980, 1180, 1420]) {
  const serit = Math.max(1, Math.floor((W + ARALIK) / (TABAN + ARALIK)));
  const olcu = (W - ARALIK * (serit - 1)) / serit;
  const span2 = 2 * olcu + ARALIK;         // izgarada: grid-column: span 2
  const yuzde = (span2 / W) * 100;          // esnek kutuda elle yazilacak taban
  console.log(
    `${String(W).padStart(9)}  ${String(serit).padStart(5)}  ` +
      `${olcu.toFixed(1).padStart(10)}  ${span2.toFixed(1).padStart(11)}  ` +
      `${yuzde.toFixed(2).padStart(24)}%`,
  );
}

console.log("\n--- ayni kart tek bir flex-basis degeriyle yazilirsa ---");
const SECILEN = 49.18; // 980px genisligine gore hesaplanan deger
console.log(`flex: 0 0 ${SECILEN}%  (980px icin dogru olan deger)`);
console.log("kapsayici  uygulanan olcu  o genislikte dogru olan  sapma");
for (const W of [640, 780, 980, 1180, 1420]) {
  const serit = Math.max(1, Math.floor((W + ARALIK) / (TABAN + ARALIK)));
  const olcu = (W - ARALIK * (serit - 1)) / serit;
  const dogru = 2 * olcu + ARALIK;
  const uygulanan = (W * SECILEN) / 100;
  const sapma = Math.round((uygulanan - dogru) * 10) / 10 || 0;
  console.log(
    `${String(W).padStart(9)}  ${uygulanan.toFixed(1).padStart(14)}  ` +
      `${dogru.toFixed(1).padStart(22)}  ${sapma.toFixed(1).padStart(6)}`,
  );
}
minmax(200px, 1fr), gap 16px — iki serit kaplayan kartin olcusu
kapsayici  serit  serit olcu  span 2 olcu  ayni sonuc icin flex-basis
      640      3       202.7        421.3                     65.83%
      780      3       249.3        514.7                     65.98%
      980      4       233.0        482.0                     49.18%
     1180      5       223.2        462.4                     39.19%
     1420      6       223.3        462.7                     32.58%

--- ayni kart tek bir flex-basis degeriyle yazilirsa ---
flex: 0 0 49.18%  (980px icin dogru olan deger)
kapsayici  uygulanan olcu  o genislikte dogru olan  sapma
      640           314.8                   421.3  -106.6
      780           383.6                   514.7  -131.1
      980           482.0                   482.0     0.0
     1180           580.3                   462.4   117.9
     1420           698.4                   462.7   235.7

Birinci tablo, “iki şerit genişliğinde” ifadesinin sabit bir oran olmadığını gösteriyor. Şerit sayısı üçken oran yüzde 66’ya yakın, altıya çıktığında yüzde 33’e iniyor. Aynı görsel istek, kapsayıcı genişliğine göre beş farklı sayı demek.

İkinci tablo bedeli ölçüyor. Bir genişlik seçilip oran ona göre yazıldığında, o genişlikte sapma sıfırdır; diğer genişliklerde 100 ile 235 birim arasında değişir. Kart, dar kapsayıcıda olması gerekenden dar, geniş kapsayıcıda olması gerekenden geniştir. Doğru sonucu her genişlikte tutturmanın yolu, oranı genişlik aralıklarına göre yeniden yazmaktır — yani düzen kararını ızgaranın hesapladığı şeyi elle hesaplayarak taklit etmektir.

Izgarada span 2 bildirimi bu hesabın hiçbirini yazmaz; şerit ölçüsü ne olursa olsun iki şerit ve aralarındaki bir aralık kadar yer kaplar.

Sıra, Yayılma ve Çakışma

Üçüncü ölçüt, ögelerin birbirini görüp görmediğidir.

Esnek kutuda ögeler tek boyutlu bir dizidir. Sıra order ile değiştirilebilir ama bir öge başka bir ögenin üstüne gelemez, iki satırı birden kaplayamaz. Izgarada ögeler hücrelere yerleşir; aynı hücreye iki öge yerleştirmek geçerlidir ve ikisi üst üste gelir. Bir görselin üzerine yazı bindirmek, konumlandırma kullanmadan yalnız ızgarayla yazılabilir.

Bir başka ayrım da erişilebilirlik tarafında sürer. Izgara Yerleşimi dersinde görüldüğü gibi görsel sıranın belge sırasından ayrılması odak sırasını bozar. Izgara bu ayrımı çok daha kolay üretir: hat numarasıyla yerleştirme, belge sırasını tamamen yok sayar. Esnek kutuda aynı riski yalnız order ve ters yönler doğurur. Modelin gücü, yanlış kullanıldığında aynı ölçüde zarar verir.

İki Modelin İç İçe Kullanımı

Ölçütler karşılaştırma gibi görünse de seçim çoğu sayfada “ikisinden biri” değildir. Sayfanın büyük bölümleri iki eksenlidir; bir bölümün içindeki düğme ve etiket dizileri tek eksenlidir. Iç içe kullanım kuralın sonucudur.

/* duzen.css — 5. adım: iki modelin iş bölümü */
.istasyon-duzeni {           /* iki eksenli: bölümler birbirine göre hizalanır */
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 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; }

.olcum-kartlari {            /* iki eksenli: kart kenarları sütun sütun hizalanır */
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--aralik-0);
}

.olcum-kartlari .ozet { grid-column: 1 / -1; }

.kart-basligi {              /* tek eksenli: başlık ve rozet aynı satırda */
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.kart-basligi .birim { margin-inline-start: auto; }

Üç kapsayıcı, üç ayrı soru. Sayfa düzeni bölümleri hem satırda hem sütunda hizalar: ızgara. Kart dizisi, kartların kenarlarının satırlar arasında çakışmasını ister: ızgara. Kart başlığındaki iki öge yalnız bir doğrultuda dizilir ve aradaki boşluk içerikten artar: esnek kutu.

Bir sınır burada belirir. Kart başlığının içindeki .birim ögesi, komşu karttaki .birim ögesiyle hizalanmaz; her kart kendi esnek hesabını yapar. Bu hizanın kurulması için iç kapsayıcının dış ızgaranın hatlarını görmesi gerekir. subgrid değeri, iç içe bir ızgaranın kendi şeritlerini tanımlamak yerine kapsayanın hatlarını devralmasını sağlar ve bu sorunu çözer. Değerin tanınıp tanınmadığı bir özellik sorgusuyla sınanır; sorgu yazımı sonraki konuda ele alınacaktır.

Karar Sırası

Seçim üç soruyla bitirilebilir ve sıraları önemlidir.

  1. Ögeler birbirine göre iki eksende hizalanacak mı? Yanıt evetse ızgara. Bu soru, kalan ikisini gereksiz kılacak kadar belirleyicidir.
  2. Ölçüyü içerik mi belirliyor? Ögelerin sayısı bilinmiyor, ölçüleri metnin uzunluğundan geliyor ve aralarındaki boşluk artan alandan dağıtılacaksa esnek kutu daha az bildirim ister.
  3. Bir öge diğerlerinden farklı bir alan mı kaplayacak? Yayılma, üst üste binme ya da belirli bir hücreye yerleştirme isteği varsa ızgara.

Ölçütlerin hiçbiri “ızgara yeni, esnek kutu eski” biçiminde bir sıralama içermez. İki model aynı düzen katmanının iki ayrı aracıdır ve birbirinin yerine geçmez.

Özet

  • Esnek kutu hesabı ögeden başlatır ve her satırı kendi içinde çözer; ızgara hesabı kapsayıcıdan başlatır ve bütün satırlara aynı hat kümesini uygular.
  • Ögeler tam bölünmediğinde iki model ayrışır: ızgarada son satırın ögeleri şerit ölçüsünü korur, esnek kutuda kalan ögeler satırı paylaşarak genişler.
  • Bir ögenin iki şerit kaplaması ızgarada tek bildirimdir; esnek kutuda karşılığı şerit sayısıyla değişen bir orandır ve tek bir değerle her genişlikte doğru olmaz.
  • Üst üste binme, belirli hücreye yerleştirme ve iki eksenli hizalama yalnız ızgarada tanımlıdır; sıra bozma riski de aynı ölçüde büyür.
  • Sayfa düzeyinde ızgara, bileşen içinde esnek kutu yaygın bir iş bölümüdür; bunun nedeni alışkanlık değil, iki düzeyin farklı sayıda eksende karar vermesidir.

Sonraki Adım

Buraya kadar düzenin birimi hep bir kutu oldu: kart, bölüm, düğme. Kutular hatlara yerleştirildi ya da eksende dağıtıldı. Ama sayfadaki metnin kendisi de düzenlenebilir bir akıştır; uzun bir açıklama paragrafı geniş bir ekranda tek satır hâlinde uzadığında okunması zorlaşır. Sonraki ders metin akışını kutulara bölmeden sütunlara ayıran modeli ele alır: sütun sayısı ile sütun genişliği arasındaki ilişki nasıl kurulur ve içerik sütunlar arasında hangi kuralla dağılır?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat