Grid: дорожки, fr и области страницы
Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.
Страница редко бывает одним рядом или одной колонкой. Шапка тянется на всю ширину, под ней рядом стоят меню и статья, внизу — подвал: раскладка идёт сразу по двум осям, и ряд здесь не собрать из одних только flex. Для двумерной раскладки в CSS есть grid: контейнер сначала размечает себя на колонки и ряды, а потом расставляет детей по клеткам. Посчитаем, сколько достаётся доле fr, поручим браузеру самому решить, сколько колонок влезет, и нарисуем страницу картой из слов. А в конце проверим, что эта карта сделала с порядком, в котором страницу читают.
Когда flex делит свободное место, размер начинается с самих элементов: у каждого есть база, а остаток соседи делят по долям. Grid заходит с другой стороны — от контейнера. Свойство display: grid делает элемент grid-контейнером, а grid-template-columns размечает его на колонки: сколько значений через пробел, столько колонок, и каждое значение — ширина своей. Колонку или ряд сетки называют дорожкой. Прямые дети контейнера занимают клетки по порядку: слева направо, ряд за рядом, — как слова в тексте.
Ряды размечают так же, свойством grid-template-rows, но чаще их не задают вовсе. Тогда браузер сам добавляет ряд, когда детям не хватило клеток, а высоту ряду даёт содержимое. Промежутки между дорожками, как и во flex, задаёт gap — сразу между колонками и между рядами. Grid — Baseline widely с 17 апреля 2020 года: пишите смело.
В сетке две колонки, 100px и 60px, промежуток 10px, а детей трое, все высотой 20px. Ширина у детей не задана. Прогноз: три строки — x, y и ширины трёх коробок.
Во flex размер начинается с элемента, и соседи делят остаток. В grid размер начинается с дорожки, а элемент заполняет свою клетку.
Кроме пикселей, ширину дорожки пишут в fr — от английского fraction, доля. Браузер считает её в два шага, и порядок шагов здесь важен. Сначала он вычитает из ширины контейнера все дорожки с явным размером и все промежутки. Потом делит остаток по числам перед fr: у 2fr две доли, у 1fr одна. Знакомая логика — flex делает то же самое, только отсчёт ведёт от баз элементов, а не от дорожек контейнера.
Сетка шириной 240px, промежуток 15px, три колонки: 60px 1fr 2fr. Прежде чем запускать, заполните последний столбец таблицы на бумаге.
| Колонка | Размер | Итоговая ширина |
|---|---|---|
| первая | 60px | ? |
| вторая | 1fr | ? |
| третья | 2fr | ? |
Прогноз — три ширины через запятую, в порядке разметки. Считать их нужно в два шага: сначала вычесть дорожку в пикселях и промежуток, потом поделить остаток на три доли.
1fr вышла уже соседней 60px: fr — не «большая резиновая колонка», а доля остатка, и остаток бывает маленьким.Во flex рост 2 не делал элемент вдвое шире соседа: доля прибавлялась к базе. Здесь 2fr ровно вдвое шире 1fr: доли делят остаток с нуля, как элементы с flex: 1, у которых база нулевая. Одинаковые колонки пишут короче: repeat(3, 1fr) — то же, что 1fr 1fr 1fr.
Ровно вдвое — пока содержимое помещается. Функция minmax(наименьший, наибольший) задаёт дорожке пределы размера. Ниже две сетки по 200px, в первой колонке каждой лежит полоса шириной 150px. У первой сетки колонки 1fr 1fr, у второй — minmax(0, 1fr) minmax(0, 1fr). Прогноз: четыре ширины — две колонки первой сетки, потом две колонки второй.
1fr — сокращение от minmax(auto, 1fr), а auto в нижнем пределе значит «не уже содержимого», как min-width: auto у flex-элемента. Полоса не дала первой колонке сжаться до 100px, и вторая получила то, что осталось. minmax(0, 1fr) опускает нижний предел до нуля: колонки снова по 100px, а полоса вылезает за край своей колонки и прячется под соседнюю — на сцене её хвоста не видно.Колонки 1fr вышли неравными — внутри есть что-то шире доли: длинное слово, картинка, таблица. Пишите minmax(0, 1fr), а само содержимое переносите или прокручивайте внутри колонки.
Каталог карточек: карточка не уже 50px, колонок — сколько влезет, и пусть они делят ширину поровну. Число колонок заранее неизвестно: на телефоне их две, на широком экране семь. Поэтому вместо числа в repeat пишут auto-fill: repeat(auto-fill, minmax(50px, 1fr)). Браузер снова считает в два шага — сначала сколько колонок наименьшего размера влезет в контейнер вместе с промежутками, потом эти колонки делят всю ширину как 1fr.
В примере одно и то же правило у двух сеток: широкой, 220px, и узкой, 130px. Промежуток 20px, в каждой по четыре карточки. Прогноз: x карточек каждой сетки — по ним видно, сколько вышло колонок.
Здесь спрятан приём, который экономит медиазапросы: одна строка repeat(auto-fill, minmax(минимум, 1fr)) даёт сетку, которая сама перестраивается под ширину. На телефоне колонок две, на планшете четыре, на широком экране семь — и ни одного @media в стилях. Медиазапросы остаются для тех случаев, когда на разных ширинах меняется сама раскладка, а не число одинаковых карточек.
Правило одно, а колонок то три, то две: сетка подстраивается под собственную ширину, и ни одного условия про размер экрана писать не пришлось. Так верстают каталоги, галереи и списки карточек.
У auto-fill есть близнец — auto-fit. Разница видна, когда карточек меньше, чем влезло колонок: auto-fill оставляет пустые колонки на месте, а auto-fit схлопывает их, и карточки растягиваются на всю ширину. Посчитаете это во второй задаче.
Теперь страница целиком. В разметке она уже поделена на ориентиры страницы: <header>, <nav>, <main>, <footer>. Grid умеет расставить их по карте, нарисованной словами. Свойство контейнера grid-template-areas получает несколько строк в кавычках: каждая строка — ряд сетки, каждое слово — клетка. Одно имя в соседних клетках сливает их в одну область. Элемент отправляют в область свойством grid-area с её именем.
Сетка шириной 240px, колонки 80px 1fr, карта из трёх рядов: шапка на две клетки, меню и основная часть рядом, подвал на две клетки. Ряды не размечены, их высоту решает содержимое: у шапки 30px, у меню 50px, у основной части 60px, у подвала 20px. Прогноз: y четырёх детей по порядку, потом ширины меню и основной части.
y, 30px. Высоту ряду даёт самый высокий из них, 60px, поэтому подвал встал на 90, а не на 80: под меню осталась полоса в 10px. Ширины пришли от колонок: 80px и 240 − 80 = 160px. Карту пишут ряд под рядом и выравнивают имена лишними пробелами: браузеру пробелы не мешают, а прямо в стилях видно, как области лягут на экране.Главная выгода карты — её видно. grid-template-areas читается как набросок страницы: строки в кавычках повторяют ряды, слова повторяют блоки, и правка раскладки становится правкой рисунка, а не арифметики. Перенести меню справа налево — значит поменять слова местами в двух строках; ни один номер колонки при этом пересчитывать не нужно. Раскладка, которую можно прочитать глазами, реже расходится с тем, что хотел дизайнер.
Область на карте — всегда прямоугольник, и во всех строках карты одинаковое число слов. Карту с областью буквой Г браузер отбрасывает целиком, как опечатку. Пустую клетку обозначают точкой.
Бывает, что внутри области лежит своя сетка, и её колонки должны встать ровно по колонкам страницы. Тогда вложенной сетке пишут grid-template-columns: subgrid: она не размечает свои дорожки, а берёт у родительской те, на которых стоит сама. Subgrid — Baseline widely с 15 марта 2026 года.
Карту на живой странице показывают инструменты разработчика. В Chrome во вкладке Elements рядом с grid-контейнером стоит значок grid: щелчок рисует поверх страницы дорожки и промежутки, а в панели Layout можно включить номера линий — границ между дорожками — и имена областей. В Firefox то же самое — во вкладке Inspector, в панели Layout, раздел Grid. Прибор такого не рисует, это ручной шаг.
Карта ставит элементы по именам, поэтому в разметке они могут стоять в любом порядке. Здесь основная часть со словом «Статья» записана первой, а шапка — второй; сетка и карта при этом те же. Проверка отвечает двумя строками: порядок в разметке и порядок на экране. Прогноз: совпадут ли они?
order во flex, только спрятано оно глубже: там свойство стоит у самого элемента, а здесь порядок разошёлся из-за карты у контейнера.Правило то же: порядок в разметке — это порядок смысла, а карта решает только, где что нарисовать. Если шапка по смыслу первая, она первая и в разметке. Есть свойство reading-flow: оно велит фокусу идти по сетке так, как её видно. Но оно есть только в Chrome и Edge, а в Firefox и Safari не сработает — это Baseline limited, не рассчитывайте на него. Обход Tab прибор не проверит: соберите такую же страницу со ссылкой в каждой области, сохраните её в файл, откройте в браузере и понажимайте Tab сами (в Safari по ссылкам ходит Option+Tab).
display: gridразмечает контейнер на дорожки:grid-template-columnsзадаёт колонки,gap— промежутки между дорожками, а ряды браузер добавляет сам, и высоту им даёт содержимое. Размер задаёт дорожка, а элемент растягивается на свою клетку. Grid — Baseline widely с апреля 2020 года.fr— доля остатка: из ширины сетки вычитаются фиксированные дорожки и все промежутки, остаток делится по числам передfr. Колонка1frможет выйти уже фиксированной.1fr— этоminmax(auto, 1fr): колонка не становится уже содержимого. Разъехавшиеся колонки чинитminmax(0, 1fr).repeat(auto-fill, minmax(50px, 1fr))считает, сколько колонок по минимуму влезет с промежутками, и делит между ними всю ширину.auto-fitвдобавок схлопывает пустые колонки.grid-template-areasрисует страницу картой: строка — ряд, слово — клетка, одно имя в соседних клетках — область-прямоугольник, и элемент встаёт в неё поgrid-area. Вложенная сетка сsubgridберёт дорожки родителя, это Baseline widely с марта 2026 года.- Карта меняет картинку, а Tab и программа чтения идут по разметке: порядок смысла задают в разметке. Сетку на живой странице показывает значок
gridв инструментах разработчика.
1/4Сетка шириной 240px, gap: 10px, колонки 40px 1fr 1fr. Какой ширины колонки?
2/4Сетка шириной 250px, gap: 10px, колонки repeat(auto-fill, minmax(100px, 1fr)), в ней пять карточек. Сколько выйдет колонок и какой ширины?
3/4В карте "head head" "nav main" "nav nav" имя nav стоит буквой Г. Что сделает браузер?
4/4Статья стоит в разметке раньше шапки, а карта рисует шапку наверху. Как сделать, чтобы и Tab начинал с шапки?
Три колонки вместо четырёх
В сетке 230px с промежутком 10px пять карточек, наименьшая ширина колонки — 50px. Сначала предскажите x пяти карточек. Потом поменяйте только наименьший размер в minmax, чтобы колонок стало три. Какие значения подходят?
Сейчас колонок четыре: 4 × 50 + 3 × 10 = 230px — ровно ширина сетки, и каждая колонка ровно 50px. Вывод — .grid div → x: 0px, 60px, 120px, 180px, 0px, пятая карточка ушла во второй ряд.
Чтобы колонок стало три, четыре не должны влезать, а три должны. Четыре не влезут, когда 4 × минимум + 30 больше 230, то есть при минимуме больше 50px. Три влезают, пока 3 × минимум + 20 не больше 230, то есть до 70px включительно. Подходит любое значение больше 50px и не больше 70px, например:
Прибор напечатает .grid div → x: 0px, 80px, 160px, 0px, 80px: три колонки по (230 − 20) / 3 = 70px. При 51px и при 70px вывод тот же, а при 71px влезут только две колонки, по 110px.
Две карточки на всю ширину
В каталоге пока две карточки, и они жмутся влево, а справа пусто. Предскажите две ширины. Потом поменяйте в правиле одно слово, чтобы карточки поделили всю ширину сетки, а минимум 50px остался. Подсказка — близнец auto-fill из третьего раздела.
Вывод — .grid div → width: 60px, 60px. По минимуму влезают три колонки: 3 × 50 + 2 × 20 = 190px. auto-fill держит все три, даже пустую: каждая (220 − 40) / 3 = 60px, а третья колонка вместе с промежутком перед ней остаётся пустым местом справа.
Теперь .grid div → width: 100px, 100px. auto-fit считает колонки так же, но пустые схлопывает до нуля вместе с их промежутками. Остаются две колонки и один промежуток: (220 − 20) / 2 = 100px. Когда карточек хватает на все колонки, пустых дорожек нет, и два слова ведут себя одинаково.
Меню справа
Перенесите меню к правому краю: основная часть слева, меню справа, той же ширины 80px. Разметку не трогайте, меняйте только правило .page. Сначала предскажите, что пример печатает сейчас.
Сейчас пример печатает nav, main → x: 0px, 80px и nav, main → width: 80px, 160px. Поменять нужно и карту, и колонки: карта говорит, какая область в какой клетке, а колонки — какой ширины клетка.
Прибор напечатает nav, main → x: 160px, 0px и прежние ширины, 80px и 160px. Если поменять только карту, меню встанет справа, но ширину 80px получит основная часть, а меню — 160px: nav, main → width: 160px, 80px.
В разметке <nav> по-прежнему стоит перед <main>, поэтому Tab сначала пройдёт по меню, хотя на экране оно справа. Если по смыслу первой должна идти статья, её переставляют в разметке, а не на карте.