Базовый Grid — строки и столбцы. Продвинутый Grid — subgrid для выравнивания вложенных элементов, именованные области для журнальных раскладок, auto-fit и minmax для автоматически адаптивных сеток без media queries.
Главная проблема вложенных сеток: дочерняя сетка не выравнивается по треки родителя. Subgrid решает это:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* Без subgrid — карточка создаёт свою независимую сетку */
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* Каждая карточка сама выравнивает строки */
}
/* С subgrid — карточка участвует в родительской сетке */
.card {
grid-row: span 3; /* Занимает 3 строки родителя */
display: grid;
grid-template-rows: subgrid; /* Использует треки РОДИТЕЛЯ */
}Теперь заголовки всех карточек находятся на одной линии, даже если текст разной длины.
.layout {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: 64px 1fr 48px;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }Точка . в template-areas обозначает пустую ячейку:
grid-template-areas:
"logo nav nav"
". hero hero"
"cards cards cards";/* auto-fill: заполняет треками, даже если элементов нет */
.gallery {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* auto-fit: схлопывает пустые треки */
.gallery {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}Разница видна при малом количестве элементов: auto-fill оставляет пустые колонки, auto-fit растягивает имеющиеся элементы.
/* Адаптивная сетка: минимум 250px, растягивается до 1fr */
/* При ширине 800px: 3 колонки. При 500px: 2 колонки. Без @media! */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
}.grid {
grid-template-columns:
[sidebar-start] 240px
[sidebar-end content-start] 1fr
[content-end aside-start] 300px
[aside-end];
}
/* Размещение по именованным линиям */
.main {
grid-column: content-start / content-end;
}.masonry {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: dense; /* Заполняет «дыры» меньшими элементами */
}
.featured {
grid-column: span 2;
grid-row: span 2;
}Без dense широкие элементы оставляют пустые ячейки. С dense браузер заполняет их следующими подходящими элементами.
.item {
grid-column: 2 / 4; /* От линии 2 до 4 */
grid-column: 2 / span 2; /* От линии 2, span на 2 колонки */
grid-row: 1 / -1; /* От первой строки до последней */
}Построение журнальной раскладки с именованными областями и вывод структуры сетки
// Журнальная раскладка через grid-template-areas
const style = document.createElement('style')
style.textContent = `
* { box-sizing: border-box; margin: 0; }
body { font-family: sans-serif; padding: 12px; }
.magazine {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: auto auto auto;
grid-template-areas:
"hero hero"
"article sidebar"
"cards cards";
gap: 12px;
max-width: 700px;
}
.hero { grid-area: hero; background: #7b2ff7; color: white; }
.article { grid-area: article; background: #dbeafe; }
.sidebar { grid-area: sidebar; background: #fef3c7; }
.cards { grid-area: cards; background: #d1fae5; }
.grid-zone {
padding: 12px;
border-radius: 6px;
font-weight: 600;
font-size: 14px;
}
`
document.head.appendChild(style)
const layout = document.createElement('div')
layout.className = 'magazine'
document.body.appendChild(layout)
const zones = [
{ area: 'hero', label: 'HERO — занимает 2 колонки' },
{ area: 'article', label: 'Основная статья' },
{ area: 'sidebar', label: 'Sidebar' },
{ area: 'cards', label: 'Карточки — занимает 2 колонки' },
]
zones.forEach(({ area, label }) => {
const zone = document.createElement('div')
zone.className = `grid-zone ${area}`
zone.textContent = label
layout.appendChild(zone)
})
// Анализируем расположение каждого элемента
console.log('=== Анализ Grid-раскладки ===')
const gridStyle = getComputedStyle(layout)
console.log('grid-template-columns:', gridStyle.gridTemplateColumns)
console.log('grid-template-rows:', gridStyle.gridTemplateRows)
// Читаем расположение каждого дочернего элемента
Array.from(layout.children).forEach(child => {
const cs = getComputedStyle(child)
console.log(`${child.className.split(' ')[1]}:`)
console.log(` grid-column: ${cs.gridColumnStart} / ${cs.gridColumnEnd}`)
console.log(` grid-row: ${cs.gridRowStart} / ${cs.gridRowEnd}`)
})
// auto-fit с minmax — адаптивная сетка без @media
const autoGrid = document.createElement('div')
autoGrid.style.cssText = `
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 8px;
margin-top: 16px;
max-width: 700px;
`
document.body.appendChild(autoGrid)
;['CSS', 'Grid', 'auto-fit', 'minmax', 'без @media'].forEach(text => {
const item = document.createElement('div')
item.textContent = text
item.style.cssText = 'background: #ede9fe; padding: 10px; border-radius: 4px; text-align: center; font-size: 13px;'
autoGrid.appendChild(item)
})
console.log('\nauto-fit grid columns:', getComputedStyle(autoGrid).gridTemplateColumns)Базовый Grid — строки и столбцы. Продвинутый Grid — subgrid для выравнивания вложенных элементов, именованные области для журнальных раскладок, auto-fit и minmax для автоматически адаптивных сеток без media queries.
Главная проблема вложенных сеток: дочерняя сетка не выравнивается по треки родителя. Subgrid решает это:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* Без subgrid — карточка создаёт свою независимую сетку */
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* Каждая карточка сама выравнивает строки */
}
/* С subgrid — карточка участвует в родительской сетке */
.card {
grid-row: span 3; /* Занимает 3 строки родителя */
display: grid;
grid-template-rows: subgrid; /* Использует треки РОДИТЕЛЯ */
}Теперь заголовки всех карточек находятся на одной линии, даже если текст разной длины.
.layout {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: 64px 1fr 48px;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }Точка . в template-areas обозначает пустую ячейку:
grid-template-areas:
"logo nav nav"
". hero hero"
"cards cards cards";/* auto-fill: заполняет треками, даже если элементов нет */
.gallery {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* auto-fit: схлопывает пустые треки */
.gallery {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}Разница видна при малом количестве элементов: auto-fill оставляет пустые колонки, auto-fit растягивает имеющиеся элементы.
/* Адаптивная сетка: минимум 250px, растягивается до 1fr */
/* При ширине 800px: 3 колонки. При 500px: 2 колонки. Без @media! */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
}.grid {
grid-template-columns:
[sidebar-start] 240px
[sidebar-end content-start] 1fr
[content-end aside-start] 300px
[aside-end];
}
/* Размещение по именованным линиям */
.main {
grid-column: content-start / content-end;
}.masonry {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: dense; /* Заполняет «дыры» меньшими элементами */
}
.featured {
grid-column: span 2;
grid-row: span 2;
}Без dense широкие элементы оставляют пустые ячейки. С dense браузер заполняет их следующими подходящими элементами.
.item {
grid-column: 2 / 4; /* От линии 2 до 4 */
grid-column: 2 / span 2; /* От линии 2, span на 2 колонки */
grid-row: 1 / -1; /* От первой строки до последней */
}Построение журнальной раскладки с именованными областями и вывод структуры сетки
// Журнальная раскладка через grid-template-areas
const style = document.createElement('style')
style.textContent = `
* { box-sizing: border-box; margin: 0; }
body { font-family: sans-serif; padding: 12px; }
.magazine {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: auto auto auto;
grid-template-areas:
"hero hero"
"article sidebar"
"cards cards";
gap: 12px;
max-width: 700px;
}
.hero { grid-area: hero; background: #7b2ff7; color: white; }
.article { grid-area: article; background: #dbeafe; }
.sidebar { grid-area: sidebar; background: #fef3c7; }
.cards { grid-area: cards; background: #d1fae5; }
.grid-zone {
padding: 12px;
border-radius: 6px;
font-weight: 600;
font-size: 14px;
}
`
document.head.appendChild(style)
const layout = document.createElement('div')
layout.className = 'magazine'
document.body.appendChild(layout)
const zones = [
{ area: 'hero', label: 'HERO — занимает 2 колонки' },
{ area: 'article', label: 'Основная статья' },
{ area: 'sidebar', label: 'Sidebar' },
{ area: 'cards', label: 'Карточки — занимает 2 колонки' },
]
zones.forEach(({ area, label }) => {
const zone = document.createElement('div')
zone.className = `grid-zone ${area}`
zone.textContent = label
layout.appendChild(zone)
})
// Анализируем расположение каждого элемента
console.log('=== Анализ Grid-раскладки ===')
const gridStyle = getComputedStyle(layout)
console.log('grid-template-columns:', gridStyle.gridTemplateColumns)
console.log('grid-template-rows:', gridStyle.gridTemplateRows)
// Читаем расположение каждого дочернего элемента
Array.from(layout.children).forEach(child => {
const cs = getComputedStyle(child)
console.log(`${child.className.split(' ')[1]}:`)
console.log(` grid-column: ${cs.gridColumnStart} / ${cs.gridColumnEnd}`)
console.log(` grid-row: ${cs.gridRowStart} / ${cs.gridRowEnd}`)
})
// auto-fit с minmax — адаптивная сетка без @media
const autoGrid = document.createElement('div')
autoGrid.style.cssText = `
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 8px;
margin-top: 16px;
max-width: 700px;
`
document.body.appendChild(autoGrid)
;['CSS', 'Grid', 'auto-fit', 'minmax', 'без @media'].forEach(text => {
const item = document.createElement('div')
item.textContent = text
item.style.cssText = 'background: #ede9fe; padding: 10px; border-radius: 4px; text-align: center; font-size: 13px;'
autoGrid.appendChild(item)
})
console.log('\nauto-fit grid columns:', getComputedStyle(autoGrid).gridTemplateColumns)Создай журнальный лейаут страницы с помощью `grid-template-areas`. Макет должен содержать: hero-секцию на всю ширину (2 колонки), основную статью и сайдбар рядом, раздел карточек на всю ширину. Используй именованные области (`grid-area`) для каждой части.
`grid-template-columns: 2fr 1fr` — две колонки. В `grid-template-areas` каждая строка в кавычках: `"hero hero"` — hero занимает обе колонки, `"article sidebar"` — рядом, `"cards cards"` — снова на всю ширину. Каждый элемент получает `grid-area: hero` (или другое имя).