От автора: недавно мне пришлось создать дизайн, похожий на газету, в котором было несколько интервалов строк и столбцов с разделительными линиями между ними. Посмотрите на рисунок макета и подумайте, придется ли вам попотеть, чтобы создать подобное. Если вы похожи на меня, вы уже давно и знаете, насколько сложно это было бы с использованием старых методов верстки.
Проект сопровождался несколькими требованиями:
Показать контуры сетки
Столбцы могут быть шире или длиннее других
Разделительные линии должны быть показаны между различными блоками
CSS Grid: обучение старого макета новым трюкам
Макеты газет могут стать головной болью, потому что обычный CSS является одномерным, что означает, что элементы перемещаются по горизонтальной или вертикальной оси. Даже современная компоновка flexbox все равно имеет одно направление.
Для такого макета нам бы хотелось, чтобы свойства, которые когда-то были предоставлены хорошими старыми таблицами HTML, давали возможность растягивать ячейки во всех направлениях. Мы также хотели бы получить преимущества современного CSS, со всей оперативностью и гибкими границами, которые могут растягиваться, чтобы заполнить доступное пространство.
Сетка CSS сочетает в себе лучшее из таблиц с лучшим из гибких блоков. На самом деле, сетка еще лучше, потому что она предоставляет свойство grid-gap для создания зазоров между ячейками, принимая во внимание доступное пространство. Каким бы мощным это ни было, как мы можем создать разделительные линии точно в середине этих желобов?
Давайте рассмотрим три метода, как это сделать.
Что мы создаем
Во-первых, мы создадим упрощенную версию дизайна газеты, которая поможет проиллюстрировать суть трех различных методов, которые мы собираемся рассмотреть. Простота этого дизайна обманчива.
Техника 1: Искусственная колонна
Это решение создает «искусственные» колонки, которые позволяют нам рисовать вертикальные линии, а затем размещать сетку поверх. Горизонтальные разделители закрашиваются при необходимости. «Искусственные» колонки создаются с использованием псевдо-селекторов в контейнере сетки.
<div class="frontpage"> <div class="fp-cell fp-cell--1"> <div class="fp-item">1</div> </div> <div class="fp-cell fp-cell--2"> <div class="fp-item">2</div> </div> <div class="fp-cell fp-cell--3 fp-cell--border-top"> <div class="fp-item">3</div> </div> <div class="fp-cell fp-cell--4 fp-cell--border-top"> <div class="fp-item">4</div> </div> </div>
Настройка линий между колонка
Давайте создадим контейнер с тремя колонками, используя display: grid и псевдо-селекторы (:before и :after), чтобы создать две колонки, которые заполняют 100% высоты контейнера.
.frontpage { position: relative; display: grid; /* Three columns */ grid-template-columns: 1fr 1fr 1fr; grid-column-gap: 32px; border: 1px solid transparent; border-top: 1px solid #DADCE0; border-bottom: 1px solid #DADCE0; overflow: hidden; } /* Two faux columns */ .frontpage:before, .frontpage:after { position: absolute; top: 0; height: 100%; content: ''; width: calc(33.3% - 4px); } .frontpage:before { left: 0; border-right: 1px solid #DADCE0; } .frontpage:after { right: 0; border-left: 1px solid #DADCE0; }
Примечание: 33% контейнера не учитывают ширину зазора, поэтому вам придется соответственно компенсировать ее.
Это рассчитывается как: 33% минус (ширина зазора разделить на (количество зазоров умножить на количество зазоров)) разделить на количество зазоров).
Или в нашем случае:
33% - (32 / (2* 2)) / 2 = 4
Вместо этого мы могли бы использовать один псевдо-селектор:
.frontpage { position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-column-gap: 32px; border: 1px solid transparent; border-top: 1px solid #DADCE0; border-bottom: 1px solid #DADCE0; overflow: hidden; } .frontpage:before { box-sizing: border-box; position: absolute; top: 0; height: 100%; content: ''; left: calc(33.3% - 5.3px); width: calc(33.3% + 10.7px); border-left: 1px solid #DADCE0; border-right: 1px solid #DADCE0; }
Примечание. При использовании только одного псевдо-селектора требуется другой расчет: один для позиционирования, а другой для ширины.
Ширина рассчитывается как: 33% плюс (количество зазоров умножить на ширина зазора) / (количество зазоров умножить на количество колонок).
Опять же, в нашем случае:
33% + (2 * 32) / (2 * 3) = 10.7
Позиция рассчитывается как: 33% минус (количество зазоров умножить на ширина зазора) / (количество зазоров умножить на количество колонок) разделить на 2).
Создаем сетку
Дизайн состоит из четырех блоков контента. Мы собираемся поместить их в контейнер и задать им класс-модификатор для использования в будущем, обеспечив, чтобы их z-index был выше, чем псевдо-селекторы сетки.
<div class="frontpage"> <div class="fp-cell fp-cell--1"></div> <div class="fp-cell fp-cell--2"></div> <div class="fp-cell fp-cell--3"></div> <div class="fp-cell fp-cell--4"></div> </div>
Теперь давайте установим белый цвет фона для ячеек (.fp-cell). Таким образом, вертикальные линии не будут просвечивать. Мы также можем установить вертикальный отступ для ячейки в 16 пикселей, который будет соответствовать половине зазора.
Первый и второй блоки контента должны иметь свои собственные уникальные охваты, как показано на схеме. Первый блок охватывает все пространство внизу, а второй блок охватывает вторую и третью колонки.
.fp-cell { position: relative; z-index: 2; padding: 16px 0; background-color: #fff; } /* Span all the way down! */ .fp-cell--1 { grid-row: 1 / span 2; } /* Span the second and third columns */ .fp-cell--2 { grid-column: 2 / span 2; }
Вертикальные разделители
Если вы посмотрите на дизайн, только для последних двух ячеек нужны горизонтальные границы. Мы можем задать им класс модификатор.
<div class="frontpage"> <div class="fp-cell fp-cell--1"></div> <div class="fp-cell fp-cell--2"></div> <div class="fp-cell fp-cell--3 fp-cell--border-top"></div> <div class="fp-cell fp-cell--4 fp-cell--border-top"></div> </div>
.fp-cell--border-top:before { content: ''; position: absolute; top: 0; left: -16px; right: -16px; border-top: 1px solid #DADCE0; }
Отрицательные поля составляют половину ширины зазора.
Техника № 2: Использование цвета фона
Еще один способ создать разделители — это использовать свойство grid-gap. Это решение не обязательно создает «реальное» расстояние между ячейками, а скорее оставляет некоторое пустое пространство, через которое может просвечиваться background-color сетки. Ширина зазора делегируется отступу внутри ячеек сетки.
<div class="container"> <div class="frontpage"> <div class="fp-cell fp-cell--1"> <div class="fp-item">1</div> </div> <div class="fp-cell fp-cell--2"> <div class="fp-item">2</div> </div> <div class="fp-cell fp-cell--3"> <div class="fp-item">3</div> </div> <div class="fp-cell fp-cell--4"> <div class="fp-item">4</div> </div> </div> </div>
.container { overflow-x: hidden; border-top: 1px solid #DADCE0; border-bottom: 1px solid #DADCE0; } .frontpage { position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 1px; margin: 0 -16px; background-color: #DADCE0; } .fp-cell { background-color: #fff; padding: 16px; } .fp-cell--1 { grid-row: 1 / span 2; } .fp-cell--2 { grid-column: 2 / span 2; } .fp-cell--3 { grid-column: 2; } .fp-item { background-color: #efefef; display: flex; align-items: center; justify-content: center; min-height: 200px; height: 100%; }
Поскольку все ячейки имеют дополнительные 16px горизонтального отступа, сетка должна быть смещена на столько же. Контейнер-оболочка позаботится о переполнении.
<div class="container"> <div class="frontpage"> <!-- ... --> </div> </div>
.container { border-top: 1px solid #DADCE0; border-bottom: 1px solid #DADCE0; overflow-x: hidden; } .frontpage { position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 1px; background-color: #DADCE0; margin: 0 -16px; }
Техника № 3: Создание границы ячейки
Это решение добавляет правую и нижнюю границу к каждой ячейке. Как и в последнем примере, grid-gap имитируется добавлением отступов к содержимому ячейки. Это означает, что они также должны быть обернуты в дополнительный контейнер.
<div class="container"> <div class="frontpage"> <div class="fp-cell fp-cell--1"> <div class="fp-item">1</div> </div> <div class="fp-cell fp-cell--2"> <div class="fp-item">2</div> </div> <div class="fp-cell fp-cell--3"> <div class="fp-item">3</div> </div> <div class="fp-cell fp-cell--4"> <div class="fp-item">4</div> </div> </div> </div>
.container { border-top: 1px solid #DADCE0; overflow-x: hidden; } .frontpage { margin: 0 -17px 0 -16px; position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; } .fp-cell { padding: 16px; background-color: #fff; border-right: 1px solid #DADCE0; border-bottom: 1px solid #DADCE0; } .fp-cell--1 { grid-row: 1 / span 2; } .fp-cell--2 { grid-column: 2 / span 2; } .fp-cell--3 { grid-column: 2; } .fp-item { background-color: #efefef; display: flex; align-items: center; justify-content: center; min-height: 200px; height: 100%; }
Как уже упоминалось, каждая ячейка имеет границы справа и снизу. Основным приемом здесь является использование для сетки (асимметричного) отрицательного поля. Это необходимо для компенсации правой границы ячейки.
.frontpage { margin: 0 -17px 0 -16px; position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; }
Заключение
Бритва Оккама предусматривает, что выигрывает самое простое решение. В нашем случае это техника номер два. Но с другой стороны, у остальных решений есть много достоинств, и они могут оказаться полезными, если, например, доступ к DOM невозможен.
Все эти методы будут работать. Выбор правильного метода зависит от конкретного варианта использования. Первый метод использует фактическое свойство grid-gap для создания зазоров, но другие, возможно, легче понять с первого взгляда … и, возможно, легче поддерживать.
Автор: Marco Troost
Источник: https://css-tricks.com
Редакция: Команда webformyself.