Удобные сетки на гридах grid — Тренажёр HTML Academy
Плавно переходим к гридам — это одна из новейших систем построения сеток. Поддерживается всеми современными браузерами, удобная и понятная, без сложных перегруженных вычислений.
В этой части мы познакомимся с этими чудесными «решётками», рассмотрим их функционал и построим уже современную сетку на гридах.
Знакомьтесь — гриды!
Главное отличие гридов от тех же флексбоксов — это их «двухмерность». На гридах мы работаем сразу и с колонками и со строками, в то время как флексы все-таки базово однострочные.
В тренажёре идет немного странное повествование — мы сначала рассматриваем поиск и заполняемость ячеек, а потом уже построение сетки. Я буду писать от создания к заполнению — мне так удобнее.
Итак, чтобы задать элементу свойства грид-контейнера указываем значение свойства display: grid;
. Сразу, в общем-то, ничего не изменится, по крайней мере визуально — элементы останутся в стандартном потоке друг за другом.
Однако, теперь наш грид-контейнер понимает свойства построения сеток. Причем, в случае грида, что дословно переводится как «сетка» или «решётка», мы будем разбивать контейнер именно на столбцы и строки.
Разделение на столбцы и ряды
Формально, как только мы задаём блоку свойство display: grid;
уже создается сетка, но с одним столбцом. Элементы внутри этого столбца переносятся в соответствии со стандартной блочной моделью.
Чтобы разделить контейнер на несколько столбцов нужно использовать свойство grid-template-columns
. Он принимает размерные значения, например, пиксели px
, проценты %
или даже auto
:
/* три стобца по 100px шириной */ grid-template-columns: 100px 100px 100px;
Каждое указанное значение — это ширина столбца, а количеством этих значений мы указываем количество столбцов.
Элементы в грид-контейнере, которые раньше занимали один столбец, теперь начнут заполнять по очереди все три столбца. При этом, если элементов больше чем столбцов, они начнут сами переноситься на новую строку, автоматически генерируя ряды:
Высота рядов при этом будет растянута так, чтобы равномерно заполнить заданную высоту контейнера. Чтобы явно задать ряды и их размеры, а не надеется на автоматическое заполнение, нужно использовать аналогичное свойство grid-template-rows
.
Работает оно абсолютно также как и grid-template-columns
, но для создания рядов. Таким образом, используя эти два свойства одновременно, можно создать сетку с определённым размером столбцов и строк.
Можно комбинировать фиксированные значения с нефиксированными, например, подставляя значение auto
, создавать относительно гибкую раскладку:
.grid-box { display: grid; grid-template-columns: 100px auto 100px; grid-template-rows: auto 100px; }
Отдельного внимания заслуживает значение доли свободного пространства fr
созданная специально для разметки грид-контейнера. Оно, судя по всему, и работает только в гридах, но это не точно.
grid-template-columns: 1fr 2fr;
В этом примере у нас два столбца со значениями fr
— первый столбец занимает одну долю, а второй две доли. Что это значит? Свойство поделило контейнер на три равные доли и «раздало» эти доли столбцам в указанных пропорциях.
Чем-то похоже на flex-grow
, но намного более понятное и без километровых расчётов. Хотя, конечно, немного менее гибкое.
Координаты грид-элементов
По умолчанию все элементы внутри грид-контейнера заполняют ячейки друг за другом, как они идут в коде. При этом, один элемент старается занять только одну ячейку, из-за чего контент может выпадать и сильно растягивать высоту.
К счастью, всем этим можно управлять! Можно задать определённому элементу где и сколько ячеек он будет занимать. Когда грид-контейнер делится на столбцы и ряды у них, очевидно, появляются границы, между которыми они и располагаются.
Эти границы имеют нумерацию, начиная от границы контейнера — слева направо для вертикальных границ и сверху вниз для горизонтальных:
Это и есть наши «координаты», которые мы можем использовать в значениях свойств. Чтобы задать явное расположение элемента на сетке, нам надо буквально указать от каких и до каких границ он будет расположен.
Свойства отвечающие за это и принимающие за значение номер границы:
grid-column-start
— указывает на начальную вертикальную границу или с какого столбца начнётся область, которую займет элемент;grid-column-end
— указывает на конечную вертикальную границу или до какого столбца включительно будет занимать место элемент;grid-row-start
— аналогично, указывает на начальную горизонтальную границу или с какого ряда начнется элемент;grid-row-end
— указывает на конечную горизонтальную границу;
На примере этой же сетки 4 на 4, чтобы расположить на ней элемент как на картинке ниже:
Нужно указать в свойствах этого элемента:
.grid-element { grid-column-start: 3; grid-column-end: 5; grid-row-start: 3; grid-row-end: 4; }
Или можно немного сократить запись, используя комбинированные свойства:
.grid-element { grid-column: 3/5; /* start/end */ grid-row: 3/4; }
Важная особенность этих свойств то, что они могут принимать и отрицательные значения. В случае указания отрицательной координаты, отсчет пойдет с конца. То есть для вертикальных справа налево и для горизонтальных снизу вверх.
Например, для того же элемента выше, эквивалентной записью будет:
.grid-element { grid-column: 3/-1; /* 1-я с конца = 5-я */ grid-row: 3/-2; /* 2-я с конца = 4-я */ }
Что будет если несколько элементов в грид-контейнере будут пересекаться в некоторых ячейках? Никакой ошибки не будет — они будут наслаиваться друг на друга в порядке как они написаны в разметке, учитывая вложенность.
Тот элемент, что задан ниже по коду будет визуально «над» всеми одноуровневыми элементами, что заданы выше по коду. Работает как слои в любом графическом редакторе.
Этими слоями можно управлять с помощью свойства z-index
, который буквально задаёт номер этого слоя. Помогает расположить элементы в нужном порядке, вывести на передний план или наоборот. Подробнее мы о нем поговорим в одной из следующих статей, совсем скоро.
Отлично! Мы научились создавать грид и размещать там элементы. Но этот метод не единственный и не самый быстрый — нужно каждому элементу прописывать начало и конец по двум осям. Попробуем по другому!
Именованные области
Немного отойдем от координат и вообще забудем про цифры. Можем ли мы как-то сказать элементу какие конкретно ячейки он должен занимать, а не в каких рамках? Можем!
В этом нам помогут два взаимосвязанных свойства — grid-template-areas
для грид-контейнера и grid-area
для элементов.
Свойство grid-template-areas
принимает необычные значения — строки. Каждая такая строка в кавычках — это ряд грид-контейнера. В строке, в свою очередь, указываются произвольные имена ячеек.
Ячейки у которых совпадает имя будут формировать область, которую заполнит элемент со значением этого имени в свойстве grid-area
. Плохо получается объяснять словами, хотя вещь супер-простая. Давайте на примере!
Создадим грид размером 4 на 4 с помощью этого свойства:
.grid-named { display: grid; grid-template-areas: "water water lava lava" "water water lava lava" "grass grass lava lava" "rocks rocks rocks rocks"; }
На всякий случай — строки можно записывать через пробел. Такая запись с переносом и отступами не обязательна, это для визуальной наглядности и читабельности.
Теперь у нас есть своего рода шаблон — 4 строки в кавычках и есть ряды, в каждой строке по 4 имени — ячейки. Где имена ячеек совпадают формируются области под элемент. Например имя «water» формирует область из четырёх ячеек.
Теперь нам нужно связать наш «шаблон» с элементами внутри контейнера. Делается это через свойство grid-area
которое указывается элементам:
.grid-element-water { grid-area: water; } .grid-element-lava { grid-area: lava; } .grid-element-grass { grid-area: grass; } .grid-element-rocks { grid-area: rocks; }
В итоге вот что у нас получается:
Элементы заняли те ячейки которые совпадали по имени из шаблона, заданного в свойстве grid-template-areas
! Таким образом сильно сокращается код — в свойстве контейнера мы разметили области, а в свойствах элементов просто связали их с этими областями.
Важный нюанс — области должны быть неразрывны и прямоугольны. Не получится задать область, например, в виде буквы «Г» или одновременно в первом и третьем столбце.
Также при формировании шаблона должны совпадать количество имён, то бишь, ячеек в строке. То есть во всех рядах должно быть одинаковое количество столбцов.
И последний нюанс — без явного указания размеров столбцов через свойство grid-template-columns
и строк через свойство grid-template-rows
, грид-контейнер будет поделён поровну, то есть каждая ячейка займет 1fr
и по горизонтали и по вертикали.
Продвинутые методы построения грида
Метод построения грида с помощью именованных зон grid-area
очень крутой, но если размерность колонок и рядов нужна отличная от 1fr
, то придется указывать свойства grid-template-columns
и grid-template-rows
.
Поэтому вернёмся к ним и подробнее поговорим о работе с ними. Дело в том, что эти замечательные свойства могут принимать очень интересные значения, которые могут сильно упростить построение даже очень сложных сеток.
Первое такое значение это функция повтора repeat()
— да, это именно функция в значении CSS свойства! В скобках она принимает два аргумента — первое, количество колонок или рядов, которое нужно создать и второе — их размер.
.grid-container { display: grid; grid-template-columns: repeat(4, 100px); /* 4 колонки по 100px */ }
Даже в таком виде полезность этой функции очевидна, но это не всё! Как мы помним, свойства грид-шаблона могут принимать несколько значений. Функция repeat()
лишь одно из них, хотя и делает сразу несколько вещей.
Таким образом, мы можем создать не просто повторяющиеся столбцы, а например, выделить один столбец или строку отдельным значением и дописать остальное повтором:
.grid-container { display: grid; grid-template-columns: 200px repeat(3, 100px); grid-template-rows: 80px repeat(4, 200px) 100px; /* Получится грид 4 на 6 */ }
Замечательно, но мы пойдем дальше! Сейчас у нас всё фиксированное — количество столбцов и строк и их размер, что не очень гибко. Из-за чего может показаться, что гриды в этом плане проигрывают флексбоксу.
Можно ли как-то задать более гибкие свойства гриду? Например, сделать так, чтобы элементы переносились с одной строки на другую в зависимости от размера окна. Ответ — можно! Делается это с помощью специального аргумента для функции repeat()
— auto-fit
, которое подставляется на место количества колонок:
.grid-container { display: grid; grid-template-columns: repeat(auto-fit, 100px); }
Этот аргумент автоматически генерирует столько столбцов шириной 100px
, сколько нужно, чтобы уместить максимально возможное количество элементов.
Если у нас, например, контейнер шириной 300px
и 4 элемента, то будет создано 3 столбца по 100px
, а 4-й элемент перенесётся на новый ряд. Если ширина контейнера увеличится до 400px
или больше, то аргумент автоматически создаст еще один столбец, куда поместится 4-й элемент.
Шикарно! Но мы пойдем еще дальше! Сейчас ширина столбцов фиксированная и в промежутках ширины не кратных 100px
, например, 380px
— у нас окажется пустое, свободное место. Как нам это исправить?
Можно задать создаваемым колонкам динамическую ширину, но не просто в процентах %
или auto
, а более умное значение-функцию minmax()
. Оно принимает два размерных значения — минимальный и максимальный размер:
.grid-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); }
В данном случае мы указали 100px
как минимальный размер колонки, которая может уместиться на строке, а за максимальный размер взяли 1fr
— колонка будет растягиваться до тех пор, пока не появится достаточно свободного места под еще одну. Таким образом, у нас не появится пустого пространства:
Заполнение ячеек и поток грида
У нас получился супер гибкий грид-контейнер, что уже чудесно. Теперь вернёмся к самим элементам и их позициям. Выше мы разбирали свойства grid-column
и grid-row
— они принимают номера границ и с их помощью мы можем точно расположить элемент на сетке.
Но в случае нашей гибкой раскладки количество этих границ меняется в зависимости от ширины контейнера. Колонок может быть 3, а может быть 8 или 12 и, соответственно, количество границ меняется.
Что делать если нужно, чтобы элемент постоянно занимал несколько ячеек? В этом случае нам поможет наследие таблиц! Свойства grid-column
и grid-row
принимают специальное значение span
, которое указывает сколько ячеек может занимать элемент:
.grid-element { grid-column: span 2; grid-row: span 2; /* займет 2 столбца и 2 строки - в сумме 4 яч. */ }
Таким образом, даже без указания координат можем создавать элементы занимающие несколько ячеек:
Кстати, работают всё те же правила «выталкивания» соседнего контента, что и в таблицах — в картинке выше ячейка 4 подвинула ячейку 5.
С этим значением неизбежно возникает проблема — если этот элемент окажется в последней ячейке на строке, то он перенесётся на новую, так как в одну он просто не поместится:
Из-за чего образуется пустота и вся наша гибкость насмарку. Однако, у этой проблемы есть решение — свойство grid-auto-flow
! Оно позволяет управлять потоком грид-контейнера и с его помощью можно этот поток изменять.
Очень сильно напоминает аналогичное свойство у флексбоксов, меняющее направление главной оси, только действует немного наоборот. Оно имеет несколько значений:
row
— значение по умолчанию, все элементы идут в ряд друг за другом и переносятся на новую строку при переполнении;column
— поворачивает поток, элементы начинают заполнять столбец, а не ряд и при переполнении генерировать новый столбец;dance
— значение немного ломающее поток, позволяет элементам размещаться так, что бы заполнить все пустые места, при этом игнорируя их порядок указанный в вёрстке:
Нюанс значения dance
в том, что порядок полностью нарушается и, например, если 2-я карточка займёт область 2×2, то вытеснит всё остальное, из-за чего порядок будет еще более хаотичный.
Поэтому следует его использовать только если порядок не имеет значения и главное заполняемость пустых мест.
Отступы и выравнивание элементов
Окончательно разобравшись с построением сетки на гридах, стоит уделить внимание нескольким крайне важным свойствам стилизации.
Первым разберём свойство gap
отвечающее за интервалы между элементами в грид-контейнере. При этом, отличие от margin
заданного отдельно элементам в том, что интервалы не появляются между границей контейнера и элементами, а только именно между ними.
То есть одним свойством gap
мы решаем большую проблему внешних отступов и их потенциального выпадения. Очень удобно. Еще удобнее то, что можно отдельно указать интервал между столбцами column-gap
и интервал между рядами row-gap
. При этом как и, например, в margin
есть короткая запись:
.grid-container { row-gap: 20px; column-gap: 50px; /* эквивалент */ gap: 20px 50px; }
Далее поговорим о выравнивании элементов в ячейках. По умолчанию бокс элемента в ячейке грид-контейнера растягивается по высоте и ширине, занимая всё пространство ячейки. Этим поведением тоже можно управлять.
В этом нам помогут свойства выравнивания:
justify-items
— задаётся контейнеру, отвечает за выравнивание всех элементов грид-контейнера по горизонтали;justify-self
— задаётся элементу, отвечает за его выравнивание по горизонтали;align-items
— задаётся контейнеру, отвечает за выравнивание всех элементов грид-контейнера по вертикали;align-self
— задаётся элементу, отвечает за его выравнивание по вертикали.
Очень похожи на свойства выравнивания и распределения у флексбокса. В тренажёре про это не сказано, но на самом деле для грид-контейнера работают все свойства и даже значения выравнивания элементов и строк флексбокса, включая, например, выравнивание строк justify-content
.
В каком-то смысле у гридов даже больше свойств, например, justify-self
работает только в гридах и не работает во флексбоксе. Значения у них все те же самые — stretch
по умолчанию, start
, end
и т. д. Не буду повторять — все они разобраны в предыдущей статье про флексы.
Испытания
Сразу замечу — это испытания части «Знакомство с гридами». Это для тех, кто возможно, проходит тренажёры как и я. На тему гридов и флексов есть еще один блок и там тоже есть испытания, о нем мы коротко поговорим в следующей статье.
В этих же испытаниях акцент на гридах как и положено по названию части. Первое испытания на понимание координат — нужно верно расположить контент на грид-раскладке.
Второе испытание на построение сетки. Причем, нам дают свободу выбора как её строить. Я сделал через именованные области, мне показалось, что так будет проще.
И третье испытание по скучнее. Опять надо угадывать циферки, в этот раз поменьше, но у меня всё еще травма после фонов. Строим небольшую сетку для секции на сайте.
Что ж, гриды мне очень зашли. Действительно, удобная и понятная технология. Понятно, что не для всех задач она подойдет, например, горизонтальные меню для хедера явно легче и проще будет сделать на флексах.
Эту статью я делал параллельно с предыдущей про флексы, поэтому она вышла так быстро. Здесь по сути компиляция двух блоков, о чем мы поговорим следом. Будем немножечко ругать тренажёры HTML Академии за их раздробленность.
А вас я могу только поблагодарить за внимание! Спасибо, что читаете или даже бегло смотрите, мне правда очень приятно.
Ссылки на предыдущие статьи по HTML Academy:
Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float
Гибкие флексбоксы display: flex
Удобные сетки на гридах display: grid <- Вы здесь
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские
...
Остальные статьи можно посмотреть у меня на главной странице блога.
Также мои соц. сетки, которые я продолжаю вести:
Мой Twitter
Мой Telegram
Мой Паблик ВК
Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!