Статьи

Создание макета Trello с помощью CSS Grid и Flexbox

В этом руководстве я познакомлю вас с реализацией базовой компоновки экрана платы Trello ( см. Пример здесь ). Это адаптивное решение, предназначенное только для CSS, и будут разработаны только структурные особенности макета.

Для предварительного просмотра вот демонстрация CodePen окончательного результата.

Экран Trello

Помимо Grid Layout и Flexbox , в решении используются модули calc и viewport . Чтобы сделать код более читабельным и эффективным, я также воспользуюсь переменными Sass .

Не предусмотрено никаких запасных вариантов, поэтому обязательно запустите код в поддерживающем браузере . Без лишних слов давайте углубимся в разработку компонентов экрана по одному.

Расположение экрана

Экран доски Trello состоит из панели приложения, панели доски и раздела, содержащего списки карт. Я построю эту структуру со следующим каркасом разметки:

<div class="ui"> <nav class="navbar app">...</nav> <nav class="navbar board">...</nav> <div class="lists"> <div class="list"> <header>...</header> <ul> <li>...</li> ... <li>...</li> </ul> <footer>...</footer> </div> </div> </div> 

Этот макет будет достигнут с помощью CSS Grid. В частности, сетка 3 × 1 (то есть один столбец и три строки). Первая строка будет для панели приложения, вторая — для панели доски, а третья — для элемента .lists .

Каждая из первых двух строк имеет фиксированную высоту, в то время как третья строка будет охватывать остальную часть доступной высоты области просмотра:

 .ui { height: 100vh; display: grid; grid-template-rows: $appbar-height $navbar-height 1fr; } 

Единицы области просмотра гарантируют, что контейнер .ui всегда будет таким же высоким, как область просмотра браузера.

Контейнер форматирования сетки назначается контейнеру, и определяются строки и столбцы сетки, указанные выше. Чтобы быть более точным, определяются только строки, поскольку нет необходимости объявлять уникальный столбец. Определение размера строк выполняется с помощью пары переменных Sass для высоты .lists и блока fr чтобы высота элемента .lists охватывала остальную часть доступной высоты области просмотра.

Раздел Списков карт

Как уже упоминалось, третий ряд сетки экрана содержит контейнер для списков карт. Вот схема его разметки:

 <div class="lists"> <div class="list"> ... </div> ... <div class="list"> ... </div> </div> 

Я использую полный однострочный контейнер строк Flexbox ширины области просмотра для форматирования списков:

 .lists { display: flex; overflow-x: auto; > * { flex: 0 0 auto; // 'rigid' lists margin-left: $gap; } &::after { content: ''; flex: 0 0 $gap; } } 

Присвоение автоматического значения свойству overflow-x указывает браузеру отображать горизонтальную полосу прокрутки внизу экрана, когда списки не соответствуют ширине, указанной в окне просмотра.

Свойство flex shorthand используется в элементах flex для придания жесткости спискам. Автоматическое значение для flex-basis .list (используется в сокращении) указывает механизму макета считывать размер из .list элемента .list , а нулевые значения для flex-grow и flex-shrink предотвращают изменение этой ширины.

Далее мне нужно добавить горизонтальное разделение между списками. Если в списках задано правое поле, то поле после последнего списка на доске с горизонтальным переполнением не отображается. Чтобы исправить это, списки разделяются левым полем, а пространство между последним списком и правым краем области просмотра обрабатывается путем добавления .lists ::after к каждому элементу .lists . Значение по умолчанию flex-shrink: 1 должно быть переопределено, иначе псевдоэлемент «поглощает» все отрицательное пространство и исчезает.

Обратите внимание, что в Firefox <54 требуется явная width: 100% для .lists чтобы обеспечить правильную визуализацию макета.

Список карт

Каждый список карт состоит из строки заголовка, последовательности карт и строки нижнего колонтитула. Следующий фрагмент кода HTML отражает эту структуру:

 <div class="list"> <header>List header</header> <ul> <li>...</li> ... <li>...</li> </ul> <footer>Add a card...</footer> </div> 

Важнейшая задача здесь — как управлять высотой списка. Верхний и нижний колонтитулы имеют фиксированную высоту (не обязательно равную). Тогда есть переменное количество карт, каждая с переменным количеством контента. Таким образом, список увеличивается и уменьшается по мере добавления или удаления карточек.

Но высота не может расти бесконечно, у нее должен быть верхний предел, который зависит от высоты элемента .lists . Как только этот предел будет достигнут, я хочу, чтобы появилась вертикальная полоса прокрутки, чтобы разрешить доступ к картам, которые переполняют список.

Это звучит как работа для свойств max-height и overflow . Но если эти свойства применяются к корневому контейнеру .list , то, когда список достигает максимальной высоты, появляется полоса прокрутки для всех элементов .list , .list верхний и нижний колонтитулы. На следующем рисунке показана неправильная боковая панель слева и правильная справа:

Неправильные и правые боковые панели

Итак, давайте вместо этого применим ограничение max-height к внутреннему <ul> . Какое значение следует использовать? Высоты верхнего и .lists колонтитула должны быть вычтены из высоты родительского контейнера списка ( .lists ):

 ul { max-height: calc(100% - #{$list-header-height} - #{$list-footer-height}); } 

Но существует проблема. Значение в процентах относится не к .lists а к родительскому элементу элемента <ul> , .list , и этот элемент не имеет определенной высоты, поэтому этот процент не может быть разрешен. Это можно исправить, сделав .list таким же высоким, как и .lists :

 .list { height: 100%; } 

Таким образом, поскольку .list всегда выше, чем .lists , независимо от его содержимого, его свойство background-color не может использоваться для цвета фона списка, но для этого можно использовать его дочерние элементы (header, footer, cards). цель.

Последняя поправка на высоту списка необходима, чтобы учесть немного пространства ( $gap ) между нижней частью списка и нижним краем области просмотра:

 .list { height: calc(100% - #{$gap} - #{$scrollbar-thickness}); } 

Дальнейшее значение $scrollbar-thickness вычитается, чтобы список не касался горизонтальной полосы прокрутки элемента .list . На самом деле, в Chrome эта полоса прокрутки «растет» внутри поля .lists . То есть значение 100% относится к высоте .lists , включая полосу прокрутки.

Вместо этого в Firefox полоса прокрутки «добавляется» за пределы. высота lists , т. е. 100% относится к высоте. lists не включая полосу прокрутки. Так что это вычитание не будет необходимым. В результате, когда полоса прокрутки видима, в Firefox визуальное пространство между нижней границей списка, которая достигла максимальной высоты, и верхней частью полосы прокрутки немного больше.

Вот соответствующие правила CSS для этого компонента:

 .list { width: $list-width; height: calc(100% - #{$gap} - #{$scrollbar-thickness}); > * { background-color: $list-bg-color; color: #333; padding: 0 $gap; } header { line-height: $list-header-height; font-size: 16px; font-weight: bold; border-top-left-radius: $list-border-radius; border-top-right-radius: $list-border-radius; } footer { line-height: $list-footer-height; border-bottom-left-radius: $list-border-radius; border-bottom-right-radius: $list-border-radius; color: #888; } ul { list-style: none; margin: 0; max-height: calc(100% - #{$list-header-height} - #{$list-footer-height}); overflow-y: auto; } } 

Как уже упоминалось, цвет фона списка отображается путем присвоения значения $list-bg-color background-color свойству background-color каждого .list элемента .list . overflow-y показывает полосу прокрутки карт только при необходимости. Наконец, некоторые простые стили добавляются в верхний и нижний колонтитулы.

Последние штрихи

HTML-код для одной карты просто состоит из элемента списка:

 <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit</li> 

Или, если на карте есть изображение обложки:

 <li> <img src="..." alt="..."> Lorem ipsum dolor sit amet </li> 

Это соответствующий CSS:

 li { background-color: #fff; padding: $gap; &:not(:last-child) { margin-bottom: $gap; } border-radius: $card-border-radius; box-shadow: 0 1px 1px rgba(0,0,0, 0.1); img { display: block; width: calc(100% + 2 * #{$gap}); margin: -$gap 0 $gap (-$gap); border-top-left-radius: $card-border-radius; border-top-right-radius: $card-border-radius; } } 

После задания фона, отступов и нижних полей макет изображения обложки готов. Ширина изображения должна охватывать всю карточку от левого края заполнения до правого края заполнения:

 width: calc(100% + 2 * #{$gap}); 

Затем назначаются отрицательные поля для выравнивания изображения по горизонтали и вертикали:

 margin: -$gap 0 $gap (-$gap); 

Третье положительное значение поля учитывает пространство между изображением обложки и текстом карточки.

Наконец, я добавил контекст гибкого форматирования к двум полосам, которые занимают первые строки макета экрана. Но они только набросаны. Не стесняйтесь создавать свою собственную реализацию этого, расширяя демонстрацию .

Вывод

Это только один из возможных способов реализации этого проекта, и было бы интересно увидеть другие подходы. Кроме того, было бы неплохо завершить макет, например, завершив две полосы экрана.

Другим потенциальным улучшением может быть реализация пользовательских полос прокрутки для списков карт.

Так что не стесняйтесь раскошелиться на демо и опубликовать ссылку в обсуждении ниже.