Skip to main content

Властивість CSS box-sizing

box-sizing визначає, чи включає зазначена width і height елемента тільки вміст, чи ще й padding та border.

Теорія

TL;DR

  • content-box (браузерний дефолт): width: 200px + padding: 20px = реальних 240px. Padding додається зовні.
  • border-box: width: 200px - це кінцевий розмір. Padding "вирізається" зсередини.
  • Аналогія: content-box - замовляєш піцу на 200px, але начинка виходить за краї; border-box - коробка рівно 200px, де все поміщається всередині.
  • Правило вибору: використовуй border-box скрізь через * { box-sizing: border-box; }. Саме так роблять Bootstrap, Tailwind і React-проекти за замовчуванням.

Швидкий приклад

css
.content-box { box-sizing: content-box; /* дефолт браузера */ width: 200px; padding: 20px; border: 5px solid; /* реальна ширина: 200 + 40 + 10 = 250px */ } .border-box { box-sizing: border-box; width: 200px; padding: 20px; border: 5px solid; /* реальна ширина: 200px, область вмісту = 150px */ }

Перший блок займає 250px. Другий - рівно 200px. Однакові значення CSS, різні моделі розрахунку розміру.

Головна різниця

Браузери за замовчуванням використовують content-box згідно зі специфікацією CSS2.1. Тому width: 200px; padding: 20px дає елемент шириною 240px. Більшість розробників очікують протилежного - звідси горизонтальний скрол на мобільних, який роками очолює рейтинг CSS-багів на StackOverflow. border-box вирішує це: число яке ти пишеш - це число яке отримуєш.

Коли що використовувати

  • Фіксовані UI-компоненти (картки, модалки, кнопки) - border-box, щоб padding не ламав лейаут.
  • Дочірні елементи flex або grid - border-box, запобігає переповненню контейнера.
  • Текстові блоки де розмір диктує вміст - тут content-box підходить, але border-box теж не завадить.
  • Глобальний reset - border-box через * є стандартом галузі. Стаття Пола Айріша 2012 року показала, що це миттєво фіксує більшість padding-багів у лейауті.

Таблиця порівняння

content-boxborder-box
Що означає widthтільки область вмістузагальний зовнішній розмір
Дефолт браузераТак (CSS2.1)Ні
Розмір вмістудорівнює widthwidth - padding - border
Коли використовуватичисто контентний розмір (рідко)99% лейаутів

Як браузер це розраховує

CSS-рушії Blink (Chrome) і Gecko (Firefox) читають box-sizing на етапі вирішення стилів. Для border-box рушій віднімає padding + border від зазначеної ширини перед тим як призначити ширину вмісту. Для content-box цей крок пропускається. Все це відбувається на фазі лейауту, до малювання, відповідно до розділу 10.2 специфікації CSS2.1.

Типові помилки

Забувають про браузерний дефолт. Пишеш width: 300px; padding: 24px і дивуєшся чому картка виходить за межі контейнера. Реальна ширина - 348px, а не 300px. Рішення: додай глобальний reset у стилі проекту.

css
/* Стандартний глобальний reset */ *, *::before, *::after { box-sizing: border-box; }

Мікс box-sizing у flexbox. Один дочірній елемент використовує content-box, інший border-box. Лейаут ламається, бо flex рахує зовнішні розміри. Задай box-sizing на контейнері та дозволь дочірнім успадкувати.

css
.flex-container { display: flex; box-sizing: border-box; /* дочірні успадковують */ } .flex-child { flex: 1; padding: 20px; /* залишається в межах flex-треку, без overflow */ }

border-box на елементах img. Зображення зазвичай не мають padding чи border. Налаштування не спричиняє багів, але зменшить простір для вмісту якщо пізніше додати padding. Краще пропустити або явно вказати content-box для зображень.

Забувають про псевдоелементи. ::before і ::after не успадковують box-sizing автоматично в старих reset-стилях. Тому сучасний патерн явно включає *::before, *::after.

Де зустрічається в реальних проектах

  • React (create-react-app, Vite) - * { box-sizing: border-box; } в index.css за замовчуванням.
  • Tailwind CSS - застосовує border-box на html і body через preflight reset.
  • Bootstrap 5 - універсальний border-box для стабільності grid.
  • Next.js - глобальний reset включає його щоб уникнути hydration-розбіжностей.
  • Material UI - картки і кнопки використовують border-box для відповідності дизайн-токенам.

Питання на співбесіді

Q: Який браузерний дефолт для box-sizing і чому це важливо?
A: content-box, успадкований з CSS2.1. Без reset кожен елемент з padding стає ширшим за зазначену ширину. Такі баги складно відстежити без знання цього дефолту.

Q: Як box-sizing взаємодіє з min-width і max-width?
A: Ті ж правила. При border-box min-width: 200px означає що загальний зовнішній розмір - щонайменше 200px. Padding і border все одно вираховуються зі вмісту всередині.

Q: Чи впливає box-sizing на ::before і ::after?
A: Так, вони успадковують значення від батька. Але старі reset-стилі таргетили тільки *. Сучасний патерн - *, *::before, *::after { box-sizing: border-box; }, щоб явно охопити псевдоелементи.

Q: Як у бібліотеці компонентів обробляти конфлікти box-sizing з користувацьким CSS?
A: Стандартний підхід - задокументувати що бібліотека очікує border-box і попросити підключити universal reset. Для повністю ізольованих компонентів Shadow DOM не дає зовнішнім стилям впливати на внутрішні. Обидва підходи використовуються в реальних бібліотеках.

Приклади

content-box проти border-box поруч

html
<!DOCTYPE html> <html> <style> .content-box { box-sizing: content-box; width: 200px; padding: 20px; border: 5px solid navy; background: lightblue; margin-bottom: 12px; } .border-box { box-sizing: border-box; width: 200px; padding: 20px; border: 5px solid darkred; background: lightcoral; } </style> <div class="content-box">Реальна ширина: 250px (вміст 200 + padding 40 + border 10)</div> <div class="border-box">Реальна ширина: 200px (padding і border поміщаються всередині)</div> </html>

Синій блок займає 250px попри width: 200px. Червоний - рівно 200px. Відкрий DevTools, наведи на обидва елементи і подивись на box model у панелі справа.

Картка як React-компонент

Поширений патерн у бібліотеках компонентів. Без border-box додавання padding змушує картку виходити за межі контейнера і зміщувати інші елементи.

jsx
function RepoCard({ name, stars }) { return ( <div style={{ boxSizing: 'border-box', /* 300px залишається 300px навіть з padding */ width: '300px', padding: '16px', border: '1px solid #ddd', borderRadius: '6px' }}> <h3>{name}</h3> <span>{stars}</span> </div> ); } // Картка завжди займає рівно 300px, без overflow у батьківському контейнері

Зміна padding при hover не зміщує лейаут. Я бачив як це спричиняло помітні стрибки в продакшені, коли хтось випадково видалив глобальний reset і всі картки на сторінці одразу розширились на 32px.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?