Subgrid

subgrid — значение для grid-template-columns или grid-template-rows, которое позволяет вложенному grid-контейнеру использовать линии родительского grid.

Зачем нужно

Без subgrid вложенные grid-контейнеры создают независимые сетки. Элементы внутри карточек не выравниваются друг с другом. Subgrid решает эту проблему: дочерний грид «наследует» линии родителя, и все вложенные элементы выстраиваются в единую сетку.

Где используется

  • Карточки с заголовком, описанием и кнопкой — все на одной высоте
  • Формы, где labels и inputs выровнены по колонкам родителя
  • Таблицы-гриды с ячейками, занимающими несколько строк
  • Любая ситуация, где вложенные элементы должны следовать сетке родителя

Предпосылки

Проблема без subgrid

<div class="cards">
  <div class="card">
    <h3>Короткий</h3>
    <p>Описание</p>
    <button>Купить</button>
  </div>
  <div class="card">
    <h3>Очень длинный заголовок карточки</h3>
    <p>Более длинное описание товара с подробностями</p>
    <button>Купить</button>
  </div>
</div>
/* Без subgrid — кнопки на разной высоте */
.cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.card {
  display: grid;
  grid-template-rows: auto 1fr auto; /* Своя независимая сетка */
}
/* Строки каждой карточки рассчитываются отдельно.
   Заголовки и кнопки НЕ выровнены между карточками */

Решение с subgrid

.cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr auto; /* Общие строки */
  gap: 20px;
}

.card {
  display: grid;
  grid-row: span 3; /* Занимает 3 строки родителя */
  grid-template-rows: subgrid; /* Использует строки родителя */
  gap: 8px;
}

/* Теперь заголовки, описания и кнопки ВСЕХ карточек
   выровнены по общим строкам */

Синтаксис

Subgrid по строкам

.child {
  display: grid;
  grid-row: span 3; /* Важно: должен занимать нужное число строк */
  grid-template-rows: subgrid;
  /* Столбцы — свои собственные */
  grid-template-columns: 1fr 1fr;
}

Subgrid по столбцам

.child {
  display: grid;
  grid-column: span 4; /* Занимает 4 столбца родителя */
  grid-template-columns: subgrid;
  /* Строки — свои собственные */
  grid-template-rows: auto auto;
}

Subgrid по обеим осям

.child {
  display: grid;
  grid-row: span 3;
  grid-column: span 2;
  grid-template-rows: subgrid;
  grid-template-columns: subgrid;
}

Подробный пример: карточки товаров

<div class="products">
  <article class="product">
    <img src="phone.jpg" alt="Телефон">
    <h3>Смартфон XYZ</h3>
    <p>Флагман 2026 года с камерой 200 МП</p>
    <span class="price">79 990 Р</span>
    <button>В корзину</button>
  </article>
  <article class="product">
    <img src="laptop.jpg" alt="Ноутбук">
    <h3>Ноутбук Pro</h3>
    <p>Для работы и учёбы</p>
    <span class="price">129 990 Р</span>
    <button>В корзину</button>
  </article>
  <article class="product">
    <img src="headphones.jpg" alt="Наушники">
    <h3>Беспроводные наушники с шумоподавлением и длинным названием</h3>
    <p>Время работы — 40 часов, активное шумоподавление, прозрачный режим</p>
    <span class="price">14 990 Р</span>
    <button>В корзину</button>
  </article>
</div>
.products {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto 1fr auto auto; /* 5 строк на карточку */
  gap: 20px;
}

.product {
  display: grid;
  grid-row: span 5;
  grid-template-rows: subgrid;
  gap: 8px;
  padding: 16px;
  border: 1px solid #e0e0e0;
  border-radius: 12px;
}

.product img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  border-radius: 8px;
}

.product .price {
  font-size: 1.25rem;
  font-weight: bold;
  color: #e74c3c;
}

.product button {
  align-self: end;
  padding: 10px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

Gap в subgrid

Subgrid наследует gap родителя, но можно переопределить:

.parent {
  display: grid;
  gap: 20px;
}

.child {
  display: grid;
  grid-template-rows: subgrid;
  gap: 8px; /* Переопределяет gap родителя для своих строк */
}

Именованные линии в subgrid

Subgrid может добавлять свои имена линий поверх родительских:

.parent {
  display: grid;
  grid-template-columns: [full-start] 1fr [content-start] 2fr [content-end] 1fr [full-end];
}

.child {
  grid-column: full-start / full-end;
  display: grid;
  grid-template-columns: subgrid [child-start]  [child-mid] [child-end];
  /* Квадратные скобки добавляют имена к линиям subgrid */
}

Когда использовать subgrid

Сценарий Нужен subgrid?
Карточки с выровненными секциями Да
Форма: label + input в колонках родителя Да
Независимые вложенные сетки Нет
Таблица с объединёнными ячейками Да
Простая сетка без вложенности Нет

Частые ошибки

  1. Забыли grid-row: span N — без указания количества строк subgrid не знает, сколько строк наследовать:
    /* ОШИБКА */
    .child {
      display: grid;
      grid-template-rows: subgrid; /* Сколько строк? */
    }
    /* ПРАВИЛЬНО */
    .child {
      grid-row: span 3;
      display: grid;
      grid-template-rows: subgrid;
    }
    
  2. Subgrid без display: grid — элемент должен быть grid-контейнером
  3. Ожидание, что subgrid наследует grid-template-areas — subgrid наследует только линии, не области
  4. Количество потомков не совпадает с количеством строк — лишние элементы создадут неявные строки

Практика

  • Создать сетку из 3 карточек с выровненными заголовками и кнопками через subgrid
  • Применить subgrid только по одной оси (строки)
  • Переопределить gap в subgrid-элементе
  • Проверить subgrid в DevTools (grid overlay показывает линии)
  • Сравнить макет с subgrid и без

Связанные темы

Ресурсы