Властивість 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-проекти за замовчуванням.
Швидкий приклад
.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-box | border-box | |
|---|---|---|
Що означає width | тільки область вмісту | загальний зовнішній розмір |
| Дефолт браузера | Так (CSS2.1) | Ні |
| Розмір вмісту | дорівнює width | width - 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 у стилі проекту.
/* Стандартний глобальний reset */
*, *::before, *::after {
box-sizing: border-box;
}Мікс box-sizing у flexbox. Один дочірній елемент використовує content-box, інший border-box. Лейаут ламається, бо flex рахує зовнішні розміри. Задай box-sizing на контейнері та дозволь дочірнім успадкувати.
.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 поруч
<!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 змушує картку виходити за межі контейнера і зміщувати інші елементи.
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.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.