İçeriğe geç
academia.sh

Ders 02 / 23

Esneklik Özellikleri

Temel ölçünün nereden geldiği, artı boş alanın büyüme katsayılarına göre bölünmesi, eksi boş alanın ölçekli daralma katsayılarıyla paylaştırılması ve en küçük ölçüye dayanan ögelerin dondurulması.

İçindekiler

Bir önceki ders, ögelerin ana eksendeki ölçülerini sabit aldı ve boş alanı hep artı buldu. Gerçek bir süzgeç çubuğunda ölçüler içerikten gelir; kapsayıcı daraldığında üç alanın toplamı kapsayıcıyı aşar ve boş alan eksiye düşer.

Bu ders, o paylaşımı yöneten üç bildirimi ele alır: temel ölçü (flex basis), büyüme katsayısı (flex grow factor) ve daralma katsayısı (flex shrink factor). Üçü birlikte tek bir soruyu yanıtlar: kapsayıcı ile ögelerin toplamı arasındaki fark hangi ögeye ne oranda yazılır?

Üç Bildirim ve Kısayolu

flex-basis ögenin dağıtımdan önceki ana eksen ölçüsüdür. Hesap bu değerden başlar; büyüme ve daralma bu değerin üzerine eklenir ya da bu değerden düşülür.

flex-grow artı boş alandan alınacak payın katsayısıdır. Varsayılanı sıfırdır: bir ögeye katsayı verilmemişse temel ölçüsünde kalır.

flex-shrink eksi boş alandan üstlenilecek payın katsayısıdır. Varsayılanı birdir: bir ögeye katsayı verilmemişse yine de daralır. İki varsayılanın asimetrik olması bilinçlidir — taşma, kendiliğinden büyümekten daha zararlıdır.

Üçü tek bildirimde yazılır ve kısayolun açılımı, tek başına yazılan değerlerden farklıdır:

// kisayol.mjs — flex kisayolunun uc bildirime acilimi
const kisayollar = [
  ["flex: 1", "1 1 0%"],
  ["flex: 2", "2 1 0%"],
  ["flex: auto", "1 1 auto"],
  ["flex: initial", "0 1 auto"],
  ["flex: none", "0 0 auto"],
  ["flex: 0 0 12rem", "0 0 12rem"],
];
for (const [yazim, acilim] of kisayollar) {
  console.log(`${yazim.padEnd(16)} -> flex-grow flex-shrink flex-basis = ${acilim}`);
}
flex: 1          -> flex-grow flex-shrink flex-basis = 1 1 0%
flex: 2          -> flex-grow flex-shrink flex-basis = 2 1 0%
flex: auto       -> flex-grow flex-shrink flex-basis = 1 1 auto
flex: initial    -> flex-grow flex-shrink flex-basis = 0 1 auto
flex: none       -> flex-grow flex-shrink flex-basis = 0 0 auto
flex: 0 0 12rem  -> flex-grow flex-shrink flex-basis = 0 0 12rem

Dikkat edilecek yer ilk satırdır: flex: 1 yazımı temel ölçüyü sıfıra çeker. Tek başına flex-grow: 1 yazmak temel ölçüyü auto bırakır. İki yazım aynı görünür ama farklı sonuç verir; farkın sayısal karşılığı dersin sonunda hesaplanacaktır.

Temel Ölçü Nereden Gelir

flex-basis: auto bir yönlendirmedir, bir ölçü değil: öge, ana eksendeki ölçü bildirimine (satır yönünde width, sütun yönünde height) bakar. O da auto ise ölçü içerikten gelir.

Sıra şudur:

  1. flex-basis bir uzunluk ya da yüzde taşıyorsa temel ölçü odur.
  2. flex-basis: auto ise ana eksendeki ölçü bildirimine bakılır.
  3. O da auto ise ögenin en büyük içerik ölçüsü (max-content size) kullanılır: metin hiç sarılmadan tek satıra yazıldığında kaplayacağı genişlik.

Temel ölçü box-sizing değerine tabidir. CSS ile Görsel Sunum kursunda kurulan border-box bildirimi yürürlükteyse iç boşluk ve kenarlık temel ölçünün içindedir; aksi durumda üstüne eklenir ve toplam taşar.

Dağıtımın Aritmetiği

Aşağıdaki program, önceki dersin süzgeç çubuğunu beş farklı kapsayıcı genişliğinde çözer. Ögelerin temel ölçüleri, büyüme ve daralma katsayıları ile en küçük ölçüleri sabittir; değişen tek şey kapsayıcıdır.

// esneme.mjs — esnek ogelerin buyume ve daralma paylarinin hesabi
const ARALIK = 16;

// her ogenin: temel olcu, buyume katsayisi, daralma katsayisi, en kucuk olcu
const ogeler = [
  { ad: "arama", temel: 180, buyume: 2, daralma: 1, enKucuk: 120 },
  { ad: "tarih", temel: 140, buyume: 1, daralma: 1, enKucuk: 100 },
  { ad: "durum", temel: 120, buyume: 1, daralma: 3, enKucuk: 64 },
];

// CSS'in "esnek uzunluklarin cozulmesi" adimi: dondurulmus ogelerle yinelemeli dagitim
function coz(kapsayici) {
  const n = ogeler.length;
  const bosAlanHam = kapsayici - ogeler.reduce((t, o) => t + o.temel, 0) - ARALIK * (n - 1);
  const buyutuluyor = bosAlanHam > 0;

  const durum = ogeler.map((o) => ({ ...o, olcu: o.temel, donmus: false }));
  let tur = 0;

  while (true) {
    tur += 1;
    const esnek = durum.filter((d) => !d.donmus);
    if (esnek.length === 0) break;

    const kullanilan = durum.reduce((t, d) => t + (d.donmus ? d.olcu : d.temel), 0);
    const kalan = kapsayici - kullanilan - ARALIK * (n - 1);

    if (buyutuluyor) {
      const toplamKatsayi = esnek.reduce((t, d) => t + d.buyume, 0);
      if (toplamKatsayi === 0) break;
      for (const d of esnek) d.olcu = d.temel + kalan * (d.buyume / toplamKatsayi);
    } else {
      // daralmada katsayi temel olcuyle olceklenir: kucuk kutu az daralir
      const toplamAgirlik = esnek.reduce((t, d) => t + d.daralma * d.temel, 0);
      if (toplamAgirlik === 0) break;
      for (const d of esnek) d.olcu = d.temel + kalan * ((d.daralma * d.temel) / toplamAgirlik);
    }

    // en kucuk olcunun altina inen oge dondurulur ve dagitim yeniden yapilir
    const ihlal = esnek.filter((d) => d.olcu < d.enKucuk);
    if (ihlal.length === 0) break;
    for (const d of ihlal) { d.olcu = d.enKucuk; d.donmus = true; }
    if (tur > 10) break;
  }

  return { bosAlanHam, tur, durum };
}

const bicim = (x) => x.toFixed(1).padStart(6);

console.log("temel olculer:", ogeler.map((o) => `${o.ad}=${o.temel}`).join("  "), ` aralik=${ARALIK}x2`);
console.log("katsayilar:   ", ogeler.map((o) => `${o.ad} buyume=${o.buyume} daralma=${o.daralma} en kucuk=${o.enKucuk}`).join("  |  "));

for (const kapsayici of [720, 560, 480, 400, 320]) {
  const { bosAlanHam, tur, durum } = coz(kapsayici);
  const toplam = durum.reduce((t, d) => t + d.olcu, 0) + ARALIK * (ogeler.length - 1);
  console.log(`\nkapsayici=${kapsayici}  ham bos alan=${bosAlanHam}  tur=${tur}`);
  for (const d of durum) {
    const pay = d.olcu - d.temel;
    const isaret = pay >= 0 ? "+" : "-";
    console.log(`  ${d.ad.padEnd(6)} olcu=${bicim(d.olcu)}  pay=${isaret}${Math.abs(pay).toFixed(1).padStart(5)}  ${d.donmus ? "dondu (en kucuk olcu)" : ""}`);
  }
  console.log(`  toplam (aralik dahil) = ${toplam.toFixed(1)}`);
}
temel olculer: arama=180  tarih=140  durum=120  aralik=16x2
katsayilar:    arama buyume=2 daralma=1 en kucuk=120  |  tarih buyume=1 daralma=1 en kucuk=100  |  durum buyume=1 daralma=3 en kucuk=64

kapsayici=720  ham bos alan=248  tur=1
  arama  olcu= 304.0  pay=+124.0  
  tarih  olcu= 202.0  pay=+ 62.0  
  durum  olcu= 182.0  pay=+ 62.0  
  toplam (aralik dahil) = 720.0

kapsayici=560  ham bos alan=88  tur=1
  arama  olcu= 224.0  pay=+ 44.0  
  tarih  olcu= 162.0  pay=+ 22.0  
  durum  olcu= 142.0  pay=+ 22.0  
  toplam (aralik dahil) = 560.0

kapsayici=480  ham bos alan=8  tur=1
  arama  olcu= 184.0  pay=+  4.0  
  tarih  olcu= 142.0  pay=+  2.0  
  durum  olcu= 122.0  pay=+  2.0  
  toplam (aralik dahil) = 480.0

kapsayici=400  ham bos alan=-72  tur=1
  arama  olcu= 160.9  pay=- 19.1  
  tarih  olcu= 125.2  pay=- 14.8  
  durum  olcu=  81.9  pay=- 38.1  
  toplam (aralik dahil) = 400.0

kapsayici=320  ham bos alan=-152  tur=3
  arama  olcu= 124.0  pay=- 56.0  
  tarih  olcu= 100.0  pay=- 40.0  dondu (en kucuk olcu)
  durum  olcu=  64.0  pay=- 56.0  dondu (en kucuk olcu)
  toplam (aralik dahil) = 320.0

Beş bloğun her birinde son satır aynı doğrulamayı yapar: ölçülerin toplamı, aralıklar dahil, kapsayıcıya eşittir. Esnek kutunun sözü budur; nasıl tuttuğu değere göre değişir.

Artı Boş Alan Katsayılara Bölünür

İlk üç blokta boş alan artıdır ve pay yalnızca büyüme katsayılarının oranına bakar. Kapsayıcı 720 iken 248 birimlik alan 2:1:12 : 1 : 1 oranında bölünür: 248×2/4=124248 \times 2/4 = 124 ve 248×1/4=62248 \times 1/4 = 62.

Buradaki sık yanılgı, payın ögenin kendi ölçüsüyle orantılı sanılmasıdır. Değildir. tarih ile durum farklı temel ölçülere sahip (140 ve 120) ama katsayıları eşit olduğu için ikisi de 62 birim alır; aradaki 20 birimlik fark dağıtımdan sonra da korunur.

Üçüncü blok bir sınır durumunu gösterir: kapsayıcı 480 iken boş alan yalnızca 8 birimdir ve paylar 4 ile 2’ye iner. Katsayı oranı aynı kalır, bölünen küçülür.

Katsayı toplamı birden küçükse boş alanın tamamı dağıtılmaz. Üç ögenin her birine flex-grow: 0.2 verilirse toplam 0,6 olur ve boş alanın yalnızca yüzde altmışı paylaşılır; kalanı kapsayıcının sonunda boşluk olarak durur.

Eksi Boş Alan Ölçekli Katsayılara Bölünür

Dördüncü blokta boş alan eksidir ve hesap değişir. Daralma payı, katsayının temel ölçüyle çarpımına göre belirlenir:

ag˘ırlıki=daralmai×temeli\text{ağırlık}_i = \text{daralma}_i \times \text{temel}_i

Kapsayıcı 400 iken ağırlıklar 1×180=1801 \times 180 = 180, 1×140=1401 \times 140 = 140 ve 3×120=3603 \times 120 = 360; toplam 680. Eksi 72 birim bu oranda bölünür: 72×360/68038,1-72 \times 360/680 \approx -38{,}1 payı durum ögesine yazılır.

Ölçekleme keyfi değildir. Katsayılar ölçekten bağımsız kullanılsaydı, eşit katsayılı iki ögeden küçük olanı büyük olanla aynı mutlak miktarda daralır ve önce sıfıra inerdi. Ölçekli katsayı, daralmayı yüzdesel olarak dengeler: her öge kendi ölçüsüyle orantılı bir yük üstlenir, katsayı bu yükü ağırlaştırır ya da hafifletir.

durum ögesinin daralma katsayısının üç olması bir tasarım kararıdır: durum rozeti, metnini kaybetmeden en çok daralabilen alandır. Arama alanı için tersi geçerlidir; oraya flex-shrink: 0 yazılsaydı hiç daralmaz ve bütün yük diğer ikisine binerdi.

Aralık daralmaz. Hesapta 32 birim her satırda sabittir; gap değeri esneme dağıtımına girmez, kapsayıcıdan baştan düşülür.

En Küçük Ölçü Dağıtımı Yeniden Başlatır

Son blok üç turda çözülüyor ve bunun nedeni çıktının son sütununda yazılı.

Birinci turda oranlı dağıtım durum ögesini 39,5 birime indirir; bu, ögenin en küçük ölçüsü olan 64’ün altındadır. Öge o değere sabitlenir ve dondurulur: artık dağıtıma katılmaz, ölçüsü kapsayıcıdan düşülür. İkinci tur kalan iki öge için tekrarlanır ve bu kez tarih ögesi 98’e inerek kendi alt sınırını ihlal eder; o da donar. Üçüncü turda tek esnek öge kalmıştır ve kalan eksiklik tümüyle ona yazılır: arama 124 birimde durur.

Bu yineleme, esnek kutunun tanımlı algoritmasıdır. İki sonucu vardır. Birincisi, bir ögenin alt sınıra dayanması diğerlerinin payını artırır; düzenin daralma davranışı doğrusal değildir. İkincisi, bütün ögeler alt sınıra dayanırsa toplam kapsayıcıyı aşar ve öge taşar — esnek kutu sözünü tutamaz.

Alt sınırın nereden geldiği ayrı bir konudur. Esnek ögede min-width değeri auto ise, sınır ögenin en küçük içerik ölçüsüne (min-content size) eşitlenir: metnin bölünebildiği en dar hâl, yani en uzun sözcüğün genişliği. Uzun bir sözcük taşıyan bir ögenin beklenenden geniş kalmasının nedeni budur ve çözümü min-width: 0 yazarak sınırı kaldırmaktır.

Sıfır Temel ile İçerik Temeli

Dersin başında bırakılan fark, aynı kapsayıcıda iki kez hesaplanabilir:

// temel.mjs — ayni katsayilarla iki farkli temel olcu
const KAP = 600, ARALIK = 16;
const adlar = ["arama", "tarih", "durum"];
const icerik = [180, 140, 120];
const katsayi = [2, 1, 1];

for (const kip of ["0%", "auto"]) {
  const temeller = kip === "0%" ? [0, 0, 0] : icerik;
  const bos = KAP - temeller.reduce((a, b) => a + b, 0) - ARALIK * 2;
  const toplam = katsayi.reduce((a, b) => a + b, 0);
  const olculer = temeller.map((t, i) => t + bos * (katsayi[i] / toplam));
  console.log(`flex-basis: ${kip.padEnd(5)} -> ${olculer.map((o, i) => `${adlar[i]}=${o.toFixed(1)}`).join("  ")}`);
}
flex-basis: 0%    -> arama=284.0  tarih=142.0  durum=142.0
flex-basis: auto  -> arama=244.0  tarih=172.0  durum=152.0

Temel ölçü sıfır olduğunda kapsayıcının tamamı dağıtılır ve son ölçüler yalnızca katsayı oranını yansıtır: eşit katsayılı iki öge eşit genişliktedir. Temel ölçü auto olduğunda önce içerik ölçüleri ayrılır, artakalan dağıtılır; içerik farkları sonuca taşınır.

Seçim ölçütü şudur: ögeler arasında içerikten bağımsız bir oran isteniyorsa temel ölçü sıfır, içerik farkları korunarak boş alan paylaşılacaksa auto yazılır. Süzgeç çubuğunda ikincisi doğrudur; alanların doğal genişlikleri anlam taşır.

/* duzen.css — 2. adım: ölçüm süzgeci */
.olcum-suzgeci {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: end;
}

.olcum-suzgeci .arama  { flex: 2 1 180px; min-inline-size: 120px; }
.olcum-suzgeci .tarih  { flex: 1 1 140px; }
.olcum-suzgeci .durum  { flex: 1 3 120px; }

Özet

  • flex-basis dağıtımdan önceki ölçüdür; auto değeri ana eksendeki ölçü bildirimine, o da auto ise en büyük içerik ölçüsüne düşer.
  • flex kısayolu tek sayıyla yazıldığında temel ölçüyü sıfıra çeker; tek başına yazılan flex-grow bildirimi temel ölçüyü auto bırakır ve iki yazım farklı sonuç verir.
  • Artı boş alan yalnızca büyüme katsayılarının oranına göre bölünür; ögelerin temel ölçüleri paya girmez ve aradaki fark dağıtımdan sonra korunur.
  • Eksi boş alan, katsayının temel ölçüyle çarpımına göre bölünür; ölçekleme, küçük ögelerin büyüklerden önce tükenmesini engeller.
  • En küçük ölçüsünün altına inen öge o değerde dondurulur ve dağıtım kalan ögelerle yeniden çalışır; esnek ögede min-width: auto sınırı en küçük içerik ölçüsüdür.

Sonraki Adım

Esnek kutu tek eksende çalışır: bir doğrultuda dağıtır, diğerinde yalnızca hizalar. Süzgeç çubuğu için bu yeterlidir, ama ölçüm sayfasının bütünü iki eksende hizalanmış bölgeler ister — künye, çizelge ve yan sütun birbirinin hem satırına hem sütununa göre yerleşmelidir. Sonraki ders, satır ve sütunları önceden tanımlayan ikinci düzen modelini kurar.

İ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