← HTML & CSS/Блочная модель CSS#21 из 383← ПредыдущийСледующий →+15 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

Блочная модель CSS

Ты задаёшь кнопке width: 200px, но она вдруг оказывается шириной 240px. Или добавляешь padding, и вёрстка разъезжается. Это классическая проблема блочной модели — и как только ты её поймёшь, такие ошибки исчезнут навсегда.

Что такое блочная модель

Каждый HTML-элемент — это прямоугольник из четырёх слоёв:

┌─────────────────────────────────┐
│           MARGIN                │  Внешний отступ (прозрачный)
│  ┌───────────────────────────┐  │
│  │         BORDER            │  │  Граница
│  │  ┌─────────────────────┐  │  │
│  │  │       PADDING       │  │  │  Внутренний отступ
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │    CONTENT    │  │  │  │  Содержимое
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘
  • Content — сам текст, картинка, дочерние элементы
  • Padding — пространство между содержимым и границей (кликабельно, получает фон элемента)
  • Border — рамка вокруг элемента (имеет ширину, стиль, цвет)
  • Margin — пространство между элементом и соседями (прозрачное, не кликабельно)
  • content-box vs border-box

    Это ключевое различие, которое всё объясняет.

    content-box (по умолчанию — и это ловушка)

    width задаёт размер только содержимого. Padding и border добавляются сверху.

    .box {
      width: 200px;
      padding: 20px;
      border: 1px solid black;
      /* Реальная ширина: 200 + 20 + 20 + 1 + 1 = 242px */
    }

    border-box (используется везде в реальных проектах)

    width — это финальный размер. Padding и border вычитаются из содержимого.

    .box {
      box-sizing: border-box;
      width: 200px;
      padding: 20px;
      border: 1px solid black;
      /* Реальная ширина: ровно 200px. Содержимое = 200 - 20 - 20 - 1 - 1 = 158px */
    }

    Глобальный сброс box-sizing

    В начале каждого CSS-файла профессионального проекта:

    *,
    *::before,
    *::after {
      box-sizing: border-box;
    }

    После этого width: 200px всегда означает финальные 200px. Так работают все CSS-фреймворки: Bootstrap, Tailwind, Material UI.

    Padding и Margin — сокращённая запись

    /* Одно значение — все стороны */
    padding: 16px;
    
    /* Два значения — вертикаль горизонталь */
    padding: 8px 16px;   /* верх/низ: 8px, лево/право: 16px */
    
    /* Четыре значения — по часовой стрелке: верх право низ лево */
    padding: 8px 16px 12px 16px;
    
    /* Явные стороны */
    padding-top: 8px;
    padding-right: 16px;
    padding-bottom: 12px;
    padding-left: 16px;

    Схлопывание margin

    Вертикальные отступы между блоками схлопываются — берётся наибольший, а не сумма:

    .block-1 { margin-bottom: 20px; }
    .block-2 { margin-top: 30px; }
    /* Расстояние между ними = 30px, а не 50px! */

    Горизонтальные margin НЕ схлопываются.

    Border

    border: 1px solid #ddd;              /* Сокращение: ширина стиль цвет */
    border-radius: 8px;                  /* Скругление углов */
    border-radius: 50%;                  /* Круг (для квадратного элемента) */
    border-top: 2px solid #7b2ff7;       /* Только сверху */
    border: none;                        /* Убрать границу */

    Типичные ошибки

    Ошибка 1: Не включить border-box и удивляться размерам

    /* Хочешь 3 колонки по 33.3%? Без border-box не получится */
    .col { width: 33.33%; padding: 16px; }  /* Суммарно > 100%, строчка ломается */
    
    /* С border-box — всё точно */
    * { box-sizing: border-box; }
    .col { width: 33.33%; padding: 16px; }  /* Работает */

    Ошибка 2: margin: auto не работает по вертикали

    /* Горизонтальное центрирование — работает */
    .container { width: 800px; margin: 0 auto; }
    
    /* Вертикальное центрирование — не работает */
    .box { height: 100px; margin: auto 0; }  /* Нет эффекта по вертикали */
    /* Для вертикального центрирования используй flexbox */

    В реальных проектах

    Инструменты разработчика Chrome (DevTools) показывают блочную модель прямо в панели Elements — цветная диаграмма с margin (оранжевый), border (жёлтый), padding (зелёный), content (синий). Открой любой сайт, нажми F12, выдели элемент — увидишь его точные размеры.

    Примеры

    content-box vs border-box: почему размеры не совпадают

    // Добавляем глобальный сброс box-sizing
    const resetStyle = document.createElement('style')
    resetStyle.textContent = '*, *::before, *::after { box-sizing: border-box; }'
    document.head.appendChild(resetStyle)
    
    // === content-box (по умолчанию ДО сброса) ===
    const contentBox = document.createElement('div')
    contentBox.style.boxSizing = 'content-box'  // явно указываем
    contentBox.style.width = '200px'
    contentBox.style.padding = '20px'
    contentBox.style.border = '5px solid #7b2ff7'
    contentBox.style.backgroundColor = '#f3e8ff'
    contentBox.style.marginBottom = '16px'
    contentBox.textContent = 'content-box: width=200px + padding + border'
    document.body.appendChild(contentBox)
    
    const cbStyle = window.getComputedStyle(contentBox)
    // Реальная ширина = 200 + 20 + 20 + 5 + 5 = 250px
    console.log('content-box — задано width:', '200px')
    console.log('content-box — реальная ширина (offsetWidth):', contentBox.offsetWidth + 'px')
    // 250px
    
    // === border-box ===
    const borderBox = document.createElement('div')
    borderBox.style.boxSizing = 'border-box'
    borderBox.style.width = '200px'
    borderBox.style.padding = '20px'
    borderBox.style.border = '5px solid #38a169'
    borderBox.style.backgroundColor = '#f0fff4'
    borderBox.textContent = 'border-box: width=200px включает всё'
    document.body.appendChild(borderBox)
    
    const bbStyle = window.getComputedStyle(borderBox)
    // Реальная ширина = ровно 200px
    console.log('border-box — задано width:', '200px')
    console.log('border-box — реальная ширина (offsetWidth):', borderBox.offsetWidth + 'px')
    // 200px
    
    // Слои блочной модели
    console.log('--- Слои блочной модели (border-box) ---')
    console.log('padding:', bbStyle.padding)             // 20px
    console.log('border:', bbStyle.borderTopWidth)       // 5px
    console.log('width (финальный):', bbStyle.width)     // 200px
    
    // Схлопывание margin
    const block1 = document.createElement('div')
    block1.style.marginBottom = '20px'
    block1.style.backgroundColor = '#fed7d7'
    block1.style.padding = '8px'
    block1.textContent = 'margin-bottom: 20px'
    
    const block2 = document.createElement('div')
    block2.style.marginTop = '30px'
    block2.style.backgroundColor = '#bee3f8'
    block2.style.padding = '8px'
    block2.textContent = 'margin-top: 30px'
    
    document.body.appendChild(block1)
    document.body.appendChild(block2)
    
    console.log('--- Схлопывание margin ---')
    console.log('block1 margin-bottom: 20px, block2 margin-top: 30px')
    console.log('Расстояние между ними = 30px (max), а не 50px (сумма)')

    Блочная модель CSS

    Ты задаёшь кнопке width: 200px, но она вдруг оказывается шириной 240px. Или добавляешь padding, и вёрстка разъезжается. Это классическая проблема блочной модели — и как только ты её поймёшь, такие ошибки исчезнут навсегда.

    Что такое блочная модель

    Каждый HTML-элемент — это прямоугольник из четырёх слоёв:

    ┌─────────────────────────────────┐
    │           MARGIN                │  Внешний отступ (прозрачный)
    │  ┌───────────────────────────┐  │
    │  │         BORDER            │  │  Граница
    │  │  ┌─────────────────────┐  │  │
    │  │  │       PADDING       │  │  │  Внутренний отступ
    │  │  │  ┌───────────────┐  │  │  │
    │  │  │  │    CONTENT    │  │  │  │  Содержимое
    │  │  │  └───────────────┘  │  │  │
    │  │  └─────────────────────┘  │  │
    │  └───────────────────────────┘  │
    └─────────────────────────────────┘
  • Content — сам текст, картинка, дочерние элементы
  • Padding — пространство между содержимым и границей (кликабельно, получает фон элемента)
  • Border — рамка вокруг элемента (имеет ширину, стиль, цвет)
  • Margin — пространство между элементом и соседями (прозрачное, не кликабельно)
  • content-box vs border-box

    Это ключевое различие, которое всё объясняет.

    content-box (по умолчанию — и это ловушка)

    width задаёт размер только содержимого. Padding и border добавляются сверху.

    .box {
      width: 200px;
      padding: 20px;
      border: 1px solid black;
      /* Реальная ширина: 200 + 20 + 20 + 1 + 1 = 242px */
    }

    border-box (используется везде в реальных проектах)

    width — это финальный размер. Padding и border вычитаются из содержимого.

    .box {
      box-sizing: border-box;
      width: 200px;
      padding: 20px;
      border: 1px solid black;
      /* Реальная ширина: ровно 200px. Содержимое = 200 - 20 - 20 - 1 - 1 = 158px */
    }

    Глобальный сброс box-sizing

    В начале каждого CSS-файла профессионального проекта:

    *,
    *::before,
    *::after {
      box-sizing: border-box;
    }

    После этого width: 200px всегда означает финальные 200px. Так работают все CSS-фреймворки: Bootstrap, Tailwind, Material UI.

    Padding и Margin — сокращённая запись

    /* Одно значение — все стороны */
    padding: 16px;
    
    /* Два значения — вертикаль горизонталь */
    padding: 8px 16px;   /* верх/низ: 8px, лево/право: 16px */
    
    /* Четыре значения — по часовой стрелке: верх право низ лево */
    padding: 8px 16px 12px 16px;
    
    /* Явные стороны */
    padding-top: 8px;
    padding-right: 16px;
    padding-bottom: 12px;
    padding-left: 16px;

    Схлопывание margin

    Вертикальные отступы между блоками схлопываются — берётся наибольший, а не сумма:

    .block-1 { margin-bottom: 20px; }
    .block-2 { margin-top: 30px; }
    /* Расстояние между ними = 30px, а не 50px! */

    Горизонтальные margin НЕ схлопываются.

    Border

    border: 1px solid #ddd;              /* Сокращение: ширина стиль цвет */
    border-radius: 8px;                  /* Скругление углов */
    border-radius: 50%;                  /* Круг (для квадратного элемента) */
    border-top: 2px solid #7b2ff7;       /* Только сверху */
    border: none;                        /* Убрать границу */

    Типичные ошибки

    Ошибка 1: Не включить border-box и удивляться размерам

    /* Хочешь 3 колонки по 33.3%? Без border-box не получится */
    .col { width: 33.33%; padding: 16px; }  /* Суммарно > 100%, строчка ломается */
    
    /* С border-box — всё точно */
    * { box-sizing: border-box; }
    .col { width: 33.33%; padding: 16px; }  /* Работает */

    Ошибка 2: margin: auto не работает по вертикали

    /* Горизонтальное центрирование — работает */
    .container { width: 800px; margin: 0 auto; }
    
    /* Вертикальное центрирование — не работает */
    .box { height: 100px; margin: auto 0; }  /* Нет эффекта по вертикали */
    /* Для вертикального центрирования используй flexbox */

    В реальных проектах

    Инструменты разработчика Chrome (DevTools) показывают блочную модель прямо в панели Elements — цветная диаграмма с margin (оранжевый), border (жёлтый), padding (зелёный), content (синий). Открой любой сайт, нажми F12, выдели элемент — увидишь его точные размеры.

    Примеры

    content-box vs border-box: почему размеры не совпадают

    // Добавляем глобальный сброс box-sizing
    const resetStyle = document.createElement('style')
    resetStyle.textContent = '*, *::before, *::after { box-sizing: border-box; }'
    document.head.appendChild(resetStyle)
    
    // === content-box (по умолчанию ДО сброса) ===
    const contentBox = document.createElement('div')
    contentBox.style.boxSizing = 'content-box'  // явно указываем
    contentBox.style.width = '200px'
    contentBox.style.padding = '20px'
    contentBox.style.border = '5px solid #7b2ff7'
    contentBox.style.backgroundColor = '#f3e8ff'
    contentBox.style.marginBottom = '16px'
    contentBox.textContent = 'content-box: width=200px + padding + border'
    document.body.appendChild(contentBox)
    
    const cbStyle = window.getComputedStyle(contentBox)
    // Реальная ширина = 200 + 20 + 20 + 5 + 5 = 250px
    console.log('content-box — задано width:', '200px')
    console.log('content-box — реальная ширина (offsetWidth):', contentBox.offsetWidth + 'px')
    // 250px
    
    // === border-box ===
    const borderBox = document.createElement('div')
    borderBox.style.boxSizing = 'border-box'
    borderBox.style.width = '200px'
    borderBox.style.padding = '20px'
    borderBox.style.border = '5px solid #38a169'
    borderBox.style.backgroundColor = '#f0fff4'
    borderBox.textContent = 'border-box: width=200px включает всё'
    document.body.appendChild(borderBox)
    
    const bbStyle = window.getComputedStyle(borderBox)
    // Реальная ширина = ровно 200px
    console.log('border-box — задано width:', '200px')
    console.log('border-box — реальная ширина (offsetWidth):', borderBox.offsetWidth + 'px')
    // 200px
    
    // Слои блочной модели
    console.log('--- Слои блочной модели (border-box) ---')
    console.log('padding:', bbStyle.padding)             // 20px
    console.log('border:', bbStyle.borderTopWidth)       // 5px
    console.log('width (финальный):', bbStyle.width)     // 200px
    
    // Схлопывание margin
    const block1 = document.createElement('div')
    block1.style.marginBottom = '20px'
    block1.style.backgroundColor = '#fed7d7'
    block1.style.padding = '8px'
    block1.textContent = 'margin-bottom: 20px'
    
    const block2 = document.createElement('div')
    block2.style.marginTop = '30px'
    block2.style.backgroundColor = '#bee3f8'
    block2.style.padding = '8px'
    block2.textContent = 'margin-top: 30px'
    
    document.body.appendChild(block1)
    document.body.appendChild(block2)
    
    console.log('--- Схлопывание margin ---')
    console.log('block1 margin-bottom: 20px, block2 margin-top: 30px')
    console.log('Расстояние между ними = 30px (max), а не 50px (сумма)')

    Задание

    Напиши HTML-страницу, демонстрирующую разницу между content-box и border-box. Создай два одинаково стилизованных блока шириной 300px, padding 20px, border 5px solid. У первого box-sizing: content-box (реальная ширина больше 300px), у второго box-sizing: border-box (реальная ширина ровно 300px). Подпиши каждый блок.

    Подсказка

    padding: 20px, border: 5px solid #7b2ff7 (или другой цвет). box-sizing: content-box у первого — реальная ширина 350px. box-sizing: border-box у второго — реальная ширина ровно 300px. Это видно в DevTools в панели Elements справа.

    Загружаем среду выполнения...
    Загружаем AI-помощника...