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:
flex-basisbir uzunluk ya da yüzde taşıyorsa temel ölçü odur.flex-basis: autoise ana eksendeki ölçü bildirimine bakılır.- O da
autoise ö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 oranında bölünür: ve .
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:
Kapsayıcı 400 iken ağırlıklar , ve
; toplam 680. Eksi 72 birim bu oranda bölünür:
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-basisdağıtımdan önceki ölçüdür;autodeğeri ana eksendeki ölçü bildirimine, o daautoise en büyük içerik ölçüsüne düşer.flexkısayolu tek sayıyla yazıldığında temel ölçüyü sıfıra çeker; tek başına yazılanflex-growbildirimi temel ölçüyüautobı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: autosı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.