Sari la conținut

De ce blocul este mai lat decât ai stabilit: modelul de cutie pe înțelesul tuturor

28 august 2026 · 8 minute · Dediu Pavel

Ai scris o lățime, iar blocul a ieșit altfel și a depășit părintele. Analizăm cum calculează browserul dimensiunea în realitate și cum găsești vinovatul în panoul dezvoltatorului în jumătate de minut.

Simptomul: am pus width: 100%, iar blocul a ieșit din ecran

Arată așa. În partea de jos a paginii a apărut o derulare orizontală. Sau o coloană a trecut de marginea din dreapta. Sau patru carduri, de câte 300 de pixeli fiecare, nu au încăput într-un container de 1160, deși 300 × 4 = 1200 și pe hârtie totul ieșea. Iar în CSS nu este nicio greșeală de tastare: valorile sunt exact cele pe care le-ai scris.

Merită să scoatem browserul de sub bănuială din start: el calculează cinstit și la fel în toate filele. Nepotrivirea apare între ceea ce ai înțeles tu prin cuvântul «lățime» și ceea ce înțelege CSS prin el. Aceste două valori sunt diferite în mod implicit, iar până nu spui altceva, se aplică valoarea implicită.

Cauza este aproape întotdeauna aceeași: scrierea width: 300px nu înseamnă «un bloc lat de 300 de pixeli». Înseamnă «300 de pixeli pentru conținutul blocului», iar spațierile și bordurile se adaugă deasupra. Să vedem de unde apare diferența, ca de acum înainte să obții numărul necesar prin calcul, nu prin încercarea lui width: 96%.

Ce consideră browserul, de fapt, lățime: content-box în mod implicit

Orice bloc are patru zone, strict în această ordine, dinspre centru spre exterior. content — zona conținutului, exact ea este stabilită implicit de width și height. padding — spațiul interior dintre conținut și bordură, colorat cu fundalul elementului. border — bordura, care ocupă loc chiar și transparentă. margin — spațiul exterior de dincolo de bordură, mereu transparent. Fiecare zonă se adaugă pe toate cele patru laturi.

Lățimea ocupată se adună astfel: width plus padding stânga și dreapta plus border stânga și dreapta. Calculăm pe un card cu width: 300px, padding: 24px și border: 1px solid: 300 + 24 + 24 + 1 + 1 = 350 de pixeli. Un rând din patru astfel de carduri ocupă 1400 — cu 240 mai mult decât containerul, și asta încă fără spațiile dintre ele. În cod scrie 300, aritmetica din cap iese, pe ecran nu.

Varianta clasică a aceleiași greșeli este width: 100% împreună cu padding: 24px pe același element. Cele o sută de procente se calculează din lățimea părintelui, iar cei 48 de pixeli de spațiere se adaugă la ea. Blocul este garantat mai lat decât părintele exact cu spațierea lui, și apare derularea orizontală.

border-box: ce se schimbă și de ce se pune global

Proprietatea box-sizing comută ce anume se consideră lățime. Valoarea implicită este content-box: width se referă la conținut, spațierile și bordurile se adaugă deasupra, iar cei 300 ai noștri devin 350. Valoarea border-box: width este lățimea totală, împreună cu spațierile și bordurile, cei 300 ai noștri rămân 300, iar conținutului îi revin 300 − 48 − 2 = 250.

A doua variantă coincide cu felul în care omul gândește dimensiunile: «cardul are 300, iar înăuntru o spațiere de 24». De aceea border-box se pune global, într-un singur rând la începutul fișierului: *, *::before, *::after { box-sizing: border-box; }. Pseudoelementele se enumeră separat, pentru că asteriscul nu le acoperă.

Merită înțeles ce nu face acest rând. El nu «micșorează blocurile» și nu «repară layout-ul» — el face ca numărul din CSS și numărul de pe ecran să coincidă. După el, 4 × 300 = 1200 — tot mai mult decât 1160, și se vede imediat că într-un rând încap trei carduri, nu patru. A devenit posibil să calculezi în minte, iar aceasta este singura justificare a regulii globale.

Este util să privim lucrurile și din cealaltă parte: cu border-box, conținutului cardului îi revin 250 de pixeli, și exact de la acest număr se calculează tot ce este înăuntru — lungimea rândului, dimensiunea fotografiei, lățimea unui buton pe tot cardul. Cu content-box știi numărul interior, dar nu și pe cel exterior, iar grila iese de fiecare dată din ochi.

Alături merită reținute și limitele. width este lățimea dorită, iar min-width și max-width sunt granițe, și ele sunt mai puternice: max-width învinge width, iar min-width le învinge pe amândouă. De aici, rândul obligatoriu pentru imagini: un img are propria dimensiune în pixeli, iar o fotografie de 1600 va rupe o coloană de 300, dacă nu scrii max-width: 100%.

De ce border-box nu te salvează de margin

margin nu intră în lățimea blocului la nicio valoare a lui box-sizing: în schemă el se află în afara bordurii. Însă ocupă loc în flux, așa că în calculul unui rând se adaugă ca termen separat: trei carduri de câte 300, cu spații de 24, înseamnă 300 × 3 + 24 × 2 = 948.

Consecința de care se împiedică lumea în mod regulat: width: 100% împreună cu margin: 16px dă întotdeauna depășire. Cele o sută de procente se calculează din lățimea părintelui, spațierile se adaugă la ele, iar border-box nu are nicio legătură — el este despre conținutul din interiorul bordurii, nu despre ce este în afara ei.

Soluția corectă nu constă, de obicei, în căutarea procentelor. Un element de tip bloc ocupă oricum toată lățimea disponibilă a părintelui, așa că width: 100% de cele mai multe ori pur și simplu nu îi trebuie: șterge rândul și spațierile vor înceta să împingă blocul în afară. A doua variantă este să muți spațierea pe părinte, sub formă de padding. A treia, cea mai previzibilă, este să stabilești distanțele prin gap la un container flex sau grid, unde această aritmetică nici nu apare.

Colapsarea marginilor: nu este un bug, iată regula

Cealaltă jumătate a întrebărilor despre dimensiuni sună altfel: «spațierea a dispărut» sau «spațierea a ieșit în afară». Ai pus titlului secțiunii margin-top: 48px, iar spațiul a apărut nu în interiorul secțiunii, ci deasupra ei: secțiunea însăși, împreună cu fundalul, a coborât, iar între marginea ei de sus și titlu este zero. Aceasta este colapsarea marginilor verticale, un comportament din specificație, mereu activ până când faci ceva care îl dezactivează.

Cazurile sunt exact trei. Frați alăturați: marginea de jos a elementului de sus și marginea de sus a celui de jos se suprapun, iar din ele rămâne cea mai mare, nu suma — 24 și 16 dau 24, nu 40. Părintele și primul sau ultimul copil: dacă între margin-top al copilului și bordura de sus a părintelui nu există nici padding, nici border, marginea iese în afară și coboară însuși părintele. Bloc gol: la un bloc fără conținut, padding, border și înălțime, propriile margini de sus și de jos colapsează una în cealaltă.

Regula pare arbitrară până când te uiți la text. Un paragraf are margini sus și jos, cam de un rând fiecare. Fără colapsare, între două paragrafe alăturate ar rezulta o distanță dublă. Colapsarea transformă «marginea de jos» și «marginea de sus» într-o singură distanță între elemente.

Ce nu colapsează: marginile orizontale — niciodată; elementele dintr-un container flex sau grid, unde marginile vecinilor se adună; elementele cu position: absolute și fixed; blocurile cu propriul context de formatare — overflow: auto sau hidden, display: flow-root, display: inline-block; și orice caz în care între două margini există padding sau border, fie și de un singur pixel.

Poți verifica asta pe cont propriu într-un minut. Ia o secțiune cu fundal și un titlu care are margine de sus și adaugă secțiunii padding-top: 1px. Marginea revine instantaneu înăuntru: între marginea copilului și marginea părintelui a apărut padding, atingerea a dispărut, iar colapsarea nu mai are ce să facă. Un pixel nu este o soluție pentru codul de producție, dar este cea mai bună dovadă că este vorba chiar de colapsare.

Concluzia practică este mai scurtă decât teoria: alege o singură direcție și ține-te de ea. Dacă toate distanțele verticale sunt stabilite prin margin-bottom, colapsarea dintre frați nu are ce să suprapună — marginea este mereu una singură și mereu cea scrisă. Regula «nu spațiem în sus» economisește mai mult timp decât cunoașterea detaliată a specificației.

Cum găsești vinovatul în 30 de secunde în DevTools

Nu trebuie să ghicești, totul se vede în browser. Dă clic dreapta pe bloc și alege «Inspectează», apoi deschide fila Computed. Chiar sus se află schema modelului de cutie: patru dreptunghiuri imbricate, de la margin în exterior până la content în centru, cu numere pe fiecare latură.

Apoi, trei pași. Primul: uită-te la dreptunghiul central — aceasta este dimensiunea reală a conținutului. Dacă este egală cu width-ul tău, în loc să fie mai mică cu spațierile, ești în content-box. Al doilea: găsește mai jos, în lista de proprietăți, rândul box-sizing — el spune direct după ce regulă se calculează lățimea. Al treilea: plimbă cursorul peste orice zonă din schemă și zona corespunzătoare se va evidenția în pagină cu propria culoare: content albastru, padding verde, border galben, margin portocaliu. O evidențiere portocalie desenată în afara părintelui este exact marginea care a ieșit în afară.

Același procedeu deosebește colapsarea de o greșeală de tastare. Dacă în Computed apare valoarea dorită a lui margin-top, iar deasupra elementului este gol — este colapsare, iar CSS-ul este corect. Dacă în Computed este zero — caută greșeala: o eroare în numele clasei, unități uitate (margin-top: 48 fără px nu se aplică) sau un selector mai puternic, care l-a învins pe al tău; proprietățile care au pierdut sunt tăiate în panoul Styles.

Exact acesta este modul de lucru pe care este construit cursul «HTML și CSS fără magie»: analizăm fluxul, modelul de cutie, flex și grid până la cauze, nu până la rețete, iar printre rezultatele cursului există un punct separat — «să explici de ce un bloc a primit exact acele dimensiuni». Modelului de cutie i se dedică acolo o lecție întreagă, cu calcule pe hârtie și verificare pe schema din Computed.

Cinci situații tipice și ce repari în fiecare

Un rezumat la care este comod să revii.

Ce au în comun toate cele cinci cazuri: mai întâi lămurim din ce s-a format numărul și abia apoi corectăm. Încercarea valorilor este proastă tocmai pentru că repară o singură lățime de ecran și lasă greșeala la toate celelalte.

Aceeași aritmetică există și în machetă, doar sub alte denumiri: spațierile interioare ale containerului și distanțele dintre elemente se stabilesc acolo prin numere, nu prin tragere cu mouse-ul. Cum arată asta din partea Figma și ce faci când blocurile se destramă deja în machetă analizăm în articolul auto layout-ul în Figma se destramă.

  • Un bloc cu width: 100% și spațieri interioare a ieșit din părinte. border-box global, la începutul fișierului. Nu căuta procente: 96% rezolvă problema la o singură lățime de ecran și se strică la alta.
  • Un rând de carduri nu încape, deși suma lățimilor iese. Recalculează lățimea ocupată, cu padding și border, iar spațiile adaugă-le ca termen separat. Dacă socoteala este incomodă — mută distanțele pe gap.
  • O imagine a rupt coloana. img { display: block; max-width: 100%; height: auto; }. Rândul display: block elimină totodată spațiul de sub imagine: implicit ea este inline și stă pe linia de bază a textului.
  • Marginea a ieșit în afara secțiunii, iar fundalul începe în alt loc. Colapsare. Dă secțiunii padding — o soluție onestă, când oricum ai nevoie de aer înăuntru — sau elimină cu totul margin-top de la primul copil.
  • Pe telefon a apărut derulare orizontală. Caută un element cu lățime fixă mai mare decât ecranul, o margine negativă sau un cuvânt lung, care nu se desparte. Containerul se stabilește mai sigur ca width: min(1160px, 100% - 32px): el se strânge împreună cu spațiile laterale.
Cursul pe această temă

HTML și CSS fără magie

11 module · 22 ore · De la zero

Vezi programa — €42