Поэтапное руководство по алгоритму автоматического размещения из CSS Grid

В этом руководстве мы рассмотрим все этапы алгоритма автоматического размещения элементов из модуля CSS Grid Layout. Каждый этап управляется с помощью свойства grid-auto-flow . В своих других статьях “Introducing the CSS Grid Layout” и “Seven Ways You Can Place Elements Using CSS Grid Layout” автор рассмотрел спецификацию CSS Grid и проанализировал, как с помощью Grid можно позиционировать элементы на веб-странице. Однако в этих материалах в сетке явным образом задавалась позиция единственного элемента. Остальные элементы размещались с помощью некоего алгоритма.
Теперь разберем этот алгоритм. И когда в следующий раз вы обнаружите, что элемент оказался не там, где нужно, вам не придётся чесать затылок и удивляться, как так произошло.
Основные принципы
Прежде чем углубляться в подробности, рассмотрим некоторые основные принципы.
-
Анонимные элементы сетки (Anonymous grid items). Если поместить текст напрямую в контейнер сетки, без обёртывания в какой-либо тег, то он превратится в анонимный элемент сетки. К таким элементам нельзя применять стили, но при этом они наследуют правила стилей от родительских контейнеров. Обратите внимание, что white space внутри контейнера сетки не приводит к созданию анонимного элемента.
Теперь активируйте в своём любимом современном браузере возможность использования экспериментальных функций, и рассмотрим подробности работы алгоритма при построении макета.
Этап #1: Генерирование анонимных элементов сетки
Первое, что делает алгоритм, когда пытается поместить все элементы в сетку, это создаёт анонимные элементы. Как упоминалось выше, вы не можете применять стили к таким элементам, потому что просто не к чему их применять.
Следующий код генерирует анонимный элемент сетки из межэлементного текста (inter-element text):
1 Anonymous Item 2 3 4 5
В этом примере нужно отметить ещё и то, что алгоритм игнорирует CSS float’ы, применённые к div 2 и div 4.
Этап #2: Размещение элементов на явно указанные позиции
Для этого и следующих нескольких этапов мы воспользуемся сеткой из девяти разных элементов.
A B C D E F G H I
Первыми в сетку будут помещены элементы, для которых явно указаны позиции. В нашем случае пусть это будут элементы А и В. Пока что проигнорируем все остальные. Зададим позиции для А и В:

Алгоритм размещает A и B в соответствии с их значениями свойства grid-area :
- На основе первого и второго значений grid-area задаёт для обоих элементов позицию левого верхнего угла.
- На основе третьего и четвёртого значений grid-area задаёт для обоих элементов позицию правого нижнего угла.
Этап #3: Размещение элементов с помощью настройки row-позиции, а не column
Теперь алгоритм размещает элемент с явно указанными row-позициями в свойствах grid-row-start и grid-row-end .
Зададим значение grid-row для элементов C и D:
Чтобы определить column-позицию, которая не задана явным образом, алгоритм действует по одному из двух сценариев в соответствии с режимом размещения (packing mode):
- Разреженное размещение (sparse packing) (по умолчанию).
- Плотное размещение (dense packing).
Разреженное размещение на этапе #3
Это поведение по умолчанию. Начальная строка столбца (column-start line) нашего элемента получит минимальный возможный индекс строки (line index). Так мы избежим взаимного наложения пространства для текущего элемента и ячеек, уже занятых другими элементами.
Начальная строка столбца также должна идти после элемента, уже размещённого в том же ряду на этом этапе. Подчеркнём: на этом этапе, а не до этого этапа.

Рассмотрим на примере: элемент D не перемещался влево от А, даже при том, что он мог бы туда поместиться без каких-либо наложений. Дело в том, что элементы с явно заданной row-позицией, а не column-, алгоритм не размещает перед другим, аналогично позиционированным в данном ряду элементом (в нашем примере — С). Если у элемента С убрать значения grid-row, тогда D переместится влево от А.
Иными словами, элемент D, у которого явно задана row-позиция, а не column, может быть помещён перед А, но только в том случае, если этому не мешает С. А в данном случае он мешает, потому что у С, как и у D, определена row-позиция, а не column, и он находится в том же ряду, что и D.
Плотное размещение на этапе #3
Если вам нужно заполнить элементом D пустое место перед A, то придётся присвоить свойству grid-auto-flow значение row dense .
.container

В этом случае начальная строка столбца снова получит минимальный возможный индекс, чтобы не было взаимных наложений с другими элементами. Но если в ряду будет пустое место, куда наш элемент может поместиться без наложений, то он будет туда помещён без учёта предыдущего элемента из того же ряда и с теми же значениями позиционирования (в нашем примере — С).
Этап #4: Определение количества столбцов в неявной сетке
Далее алгоритм пытается определить количество столбцов в неявной сетке. Это происходит так:
- Алгоритм берёт количество столбцов в явной сетке.
- Затем проходит по всем элементам с заданной column-позицией и добавляет столбцы в начало и конец явной сетки, чтобы охватить все элементы.
- Потом алгоритм проходит по всем элементам без заданной column-позиции. Если самое большое значение интервала (span) у одного из них оказывается больше ширины неявной сетки, то алгоритм добавляет столбцы в конце, чтобы охватить этот интервал.
Этап #5: Размещение оставшихся элементов
К данному моменту алгоритм уже разместил все элементы, чьи позиции явно определены, а также элементы с известными row-позициями. Теперь он начинает размещать в сетке оставшиеся элементы.
Но прежде чем рассматривать этот процесс, введём новый термин: курсор авторазмещения (auto-placement cursor). Это текущая точка вставки в сетку, определяемая пересечением пары координат — ряда и столбца. Изначально курсор помещается в точку пересечения начальных ряда и столбца неявной сетки.
Напомним, что позиционирование элементов зависит от режима размещения (packing mode), задаваемого свойством grid-auto-flow .
Разреженное размещение на этапе #5
По умолчанию оставшиеся элементы размещаются в разреженном режиме. Вот как это происходит.
Если для элемента не задана позиция ни по одной оси:
-
Алгоритм инкрементирует column-позицию курсора до тех пор:
а) пока не возникнет наложения между текущим элементом и ранее размещёнными,
б) либо пока сумма «значение column-позиции курсора + значение column-интервала элемента» не превысит количество столбцов неявной сетки.
-
Значение column-позиции курсора присваивается значению строки column-start элемента. Если значение новой позиции получается меньше, чем предыдущая column-позиция курсора, то row-позиция увеличивается на 1.

Размещение элементов E и F, когда не заданы позиции ни по одной оси
При обработке элемента E, у которого не заданы ни column-, ни row-позиция, для курсора задаются значения row 1 и column 1. Элемент E занимает только одну ячейку, он может поместиться в левый верхний угол без наложений. То есть алгоритм просто помещает элемент E на позицию row 1 / column 1.
Следующий элемент без заданных позиций по обеим осям — F. Значение column-позиции курсора увеличивается до 2. Но позиция row 1 / column 2 уже занята элементом А. Алгоритму приходится снова увеличивать значение column-позиции, пока оно не достигнет 4. Больше столбцов нет, и тогда row-позиция курсора увеличивается на 1, а column-позиция сбрасывается до 1: row 2 / column 1. Алгоритм снова начинает увеличивать column-позицию на 1, пока не дойдёт до 4. Место с координатами row 2 / column 4 пока что свободно и может быть занято элементом F. Алгоритм помещает его и переходит к следующему элементу.
Размещение элементов G и H, когда задана column-позиция
Начнём с G. Значение column-позиции курсора определяется таким же, как свойство grid-column-start элемента G — 3. Поскольку они меньше, чем предыдущее значение column (4), то row-позиция увеличивается на 1. То есть становится row 3 / column 3. Пространство с такими координатами в данный момент свободно, и G может быть туда помещён без наложений, что алгоритм и делает. Затем всё то же самое повторяется для элемента H.
Плотное размещение на этапе #5
Когда свойству grid-auto-flow присваивается значение row dense , выполняется иной порядок действий. Если вставляемый элемент не имеет определённой позиции, то текущая позиция курсора определяется в соответствии со строкой на пересечении начальных ряда и столбца неявной сетки, до того, как будет определена позиция элемента.

Элемент I помещён слева от H, потому что позиция курсора сбрасывается на строку, находящуюся на пересечении начальных ряда и столбца неявной сетки, вместо того чтобы начинать с последнего размещённого элемента. Алгоритм ищет подходящую позицию без наложений, находит место слева от H и помещает там элемент.
Заключение
В этой статье мы прошли по всем этапам работы алгоритма автоматического размещения из модуля CSS Grid Layout. Этот алгоритм управляется с помощью свойства grid-auto-flow .
Попробуйте сами вычислить последнюю позицию разных элементов из разных макетов, чтобы лучше понять работу алгоритма.
- Блог компании NIX
- Веб-разработка
- CSS
Полное визуальное руководство/шпаргалка по CSS Grid
Сегодня мы с вами рассмотрим свойства CSS Grid (далее также — Грид), позволяющие создавать адаптивные или отзывчивые макеты веб-страниц. Я постараюсь кратко, но полно объяснить, как работает каждое свойство.
Что такое CSS Grid ?
Грид — это макет для сайта (его схема, проект).
Грид-модель позволяет размещать контент сайта (располагать его определенным образом, позиционировать). Она позволяет создавать структуры, необходимые для обеспечения отзывчивости сайтов на различных устройствах. Это означает, что сайт будет одинаково хорошо смотреться на компьютере, телефоне и планшете.
Вот простой пример макета сайта, созданного с помощью Грида.
Компьютер
Телефон
Архитектура CSS Grid
Как же Грид работает? Элементы Грида (grid items) располагаются вдоль главной или основной (main) и поперечной (cross) оси (axis). При помощи различных свойств мы можем манипулировать элементами для создания макетов.
Помимо прочего, у нас имеется возможность объединять строки и колонки подобно тому, как мы это делаем в Excel , что предоставляет нам большую гибкость, чем Флекс ( Flexbox ).
К слову, если вас интересует Флекс, вот соответствующая статья.
Схема CSS Grid
Схема содержит все возможные свойства, предоставляемые Гридом. Эти свойства делятся на:
- родительские (свойства грид-контейнера) и
- дочерние (свойства грид-элементов)
Обратите внимание: красным цветом отмечены сокращения для свойств:
К концу настоящей статьи у вас будет полное понимание того, как работает каждое из них.
Настройка проекта
Для данного проекта требуются начальные знания HTML , CSS и умение работать с VSCode (или другим редактором по вашему вкусу). Делаем следующее:
- Создаем директорию для проекта, например, Project1 и открываем ее в редакторе ( cd Project1 , code . )
- Создаем файлы index.html и style.css
- Устанавливаем в VSCode сервер для разработки ( Live Server , расширение) и запускаем его
Или вы можете просто открыть Codepen (или любую другую песочницу) и начать писать код.
Все готово, можно приступать к делу.
HTML
Создаем 3 контейнера внутри body :
A B C
CSS свойство grid-auto-flow
CSS свойство grid-auto-flow определяет, как работает алгоритм автоматического размещения для неявно созданных элементов макета, указывая как они будут размещены в сетке макета.
Для того, чтобы задать размер неявно созданных столбцов в контейнере сетки макета Вы можете воспользоваться свойством grid-auto-columns, а для указания размера неявно созданных строк используется свойство grid-auto-rows.
Поддержка браузерами
| Свойство | Chrome | Firefox | Opera | Safari | IExplorer | Edge |
|---|---|---|---|---|---|---|
| grid-auto-flow | 54.0* | 52.0 | 44.0 | 10.3 | 10.0* -ms- |
16.0 12.0 -ms- |
Синтаксис:
CSS синтаксис:
grid-auto-flow: "row | column | row dense | column dense | initial | inherit";
JavaScript синтаксис:
object.style.gridAutoFlow nam">row"
Значения свойства
| Значение | Описание |
|---|---|
| row | Ключевое слово, которое указывает, что алгоритм автоматического размещения размещает элементы, заполняя каждую строку по очереди, добавляя новые строки по мере необходимости. Является значением по умолчанию. |
| column | Ключевое слово, которое указывает, что алгоритм автоматического размещения размещает элементы, заполняя каждый столбец по очереди, добавляя новые столбцы по мере необходимости. |
| dense | Ключевое слово, указывающее, что алгоритм автоматического размещения использует «плотный» алгоритм размещения элементов, который пытается заполнить ранее образованные пустоты в сетке, если далее в макете появятся подходящие по размеру элементы. Это может привести к появлению элементов не в порядке их указания, при этом заполняются отверстия, оставленные большими элементами. Если это ключевое слово dense опущено, то используется «разреженный» алгоритм, который размещает элементы в сетки не отступая для заполнения пустот. Это гарантирует, что все автоматически размещенные элементы отображаются «по порядку», даже если это оставляет пустоты, которые могли бы быть заполнены более поздними элементами. |
| initial | Устанавливает свойство в значение по умолчанию. |
| inherit | Указывает, что значение наследуется от родительского элемента. |
Версия CSS
Кандидат в рекомендации (Candidate Recommendation)
Наследуется
Анимируемое
Пример использования
Использование свойства grid-auto-flow .grid-container display: grid; /* элемент отображается как блочный grid-контейнер */ margin-top: 5px; /* внешний отступ сверху */ padding: 10px; /* внешний отступ элемента со всех сторон */ background: rgb(0,150,208); /* цвет заднего фона */ > .grid-container > div background: rgb(241,101,41); /* цвет заднего фона */ border: 1px solid #000; /* сплошная граница размером 1 пиксель черного цвета */ text-align: center; /* горизонтальное выравнивание текста */ > .grid-container grid-template: repeat(4, 1fr) / 1fr 1fr; /* определяем количество и ширину столбцов и строк в макете сетки */ grid-auto-flow: column; /* алгоритм автоматического размещения размещает элементы, заполняя каждый столбец по очереди */ > .item-a grid-row-start: 2; /* определяем с какой строки будет начинаться элемент background: red !important; /* цвет заднего фона */ > .item-b grid-column-start: 2; /* определяем с какого столбца будет начинаться элемент background: yellow !important; /* цвет заднего фона */ > "direction" onchange="changeGridAutoFlow()"> value="column">column value="row">row id="dense" type="checkbox" onchange="changeGridAutoFlow()">dense class = "grid-container">class = "item-a">Aclass = "item-b">B C D E Ffunction changeGridAutoFlow() const grid = document.getElementsByClassName("grid-container")[0], // находим первый элемент с классом grid-container direction = document.getElementById("direction"), // находим элемент с id direction dense = document.getElementById("dense"); // находим элемент с id dense let gridAutoFlow = direction.value === "row" ? "row" : "column"; // проверяем значение элемента и записываем значение в переменную в зависимости от этого значения if ( dense.checked) // проверяем выбран ли чекбокс gridAutoFlow + nam">dense"; // если да, то добавляем к значению значение dense > grid.style.gridAutoFlow = gridAutoFlow; // устанавливаем grid-контейнеру новое значение свойства grid-auto-flow >