Реализация колонок в Angular с использованием Angular CDK
В данной статье приведу решение для реализации колонок в Angular, используя breakpoints из Angular CDK.
В результате будет следующее решение:
Ранее я уже писал о реализации колонок как в Bootstrap — Banx. Создание базового лейаута в Angular, а также использовал данное решение в цикле статей про тестовое задание — Тестовое задание на Angular. Создание UI kit для приложения.
Однако, попользовавшись выше приведенными решениями, я пришел к выводу, что нужно 3 устройства (экрана) — мобильное устройство, планшет и пк. То огромное множество вариантов, которое есть в Bootstrap’е избыточно, при этом, если охота использовать инкапсуляцию стилей, то необходимо минимизировать количество экранов.
Google рекомендует 3 экрана. Совпадение? Не думаю.
Предыдущей статье я разбирал примеры использования breakpoints из Angular CDK — Создание лейаутов и сеток с помощью Angular CDK и Angular Material. Если коротко, то CDK представляет следующий объект:
В данной статье рассмотрели представленные варианты размеров из AngularВ данном случае имеется следующая таблица:
Если добавить немного mixin’ов, то можно использовать данные размеры для создания колонок под конкретные устройства.
Создание Grid модуля
Для создания сетки с изменением платформы создадим новый модуль:
ng g m grid
Добавим модули строк и столбцов:
ng g m row
ng g c row
ng g m column
ng g c column
Если использовать Nx, тогда можно все это вынести в отдельную либу и команды будут следующими:
nx g lib ui/grid
nx g m row --project=ui-grid
nx g c row --project=ui-grid
nx g m column --project=ui-grid
nx g c column --project=ui-grid
Теперь создадим 3 директивы, которые будут указывать на применимость устройства, то есть если будет у компонента с колонкой директива tablet='2'
это будет говорить о том, что это на планшете колонка будет равна 2.
ng g d handset
ng g d tablet
ng g d web
В итоге получим следующие директивы:
Как видно из реализация, каждая директива представляет собой атрибут, который может принимать значение:
private size!: string | number | undefined;
@Input() set web(size: string | number | undefined) {
this.size = size;
}
@HostBinding('class.web') get isWeb(): boolean {
return typeof this.size === 'number' || typeof this.size === 'string';
}
В примере выше видно, что директива WebDirective
добавляет соответствующий класс — @HostBinding(‘class.web’)
.
Интегрируем логику работы с колонками.
Принцип работы колонок прост:
- Есть родитель, который имеет свойство display: flex. У родителя есть отрицательные отступы слева и справа.
- У потомков есть положительные отступы слева и справа.
Тогда RowComponent
:
Как видно, у класса строки есть свойство no-padding, которое обнуляет отступы слева и справа.
В данном случае важна реализация SCSS
:
@use 'libs/ui/stylesheets/mixins' as store-mixins;
@use 'sass:math' as math;
@mixin make-row($breakpoint) {
&[#{$breakpoint}] {
display: flex;
flex-direction: row;
flex-wrap: wrap;
height: 100%;
margin-left: -1rem;
margin-right: -1rem;
}
&[#{$breakpoint}].no-padding {
margin-left: 0;
margin-right: 0;
}
}
:host {
@include store-mixins.media-handset-up() {
@include make-row(handset);
}
@include store-mixins.media-tablet-up() {
@include make-row(tablet);
}
@include store-mixins.media-web-up() {
@include make-row(web);
}
}
Используя имя директивы в качестве селектора, можно навешивать разные CSS стили. Из-за того, что директива принимает значение, можно реализовать колонки. В данном случае мы получим следующий CSS
:
[banshop-row][tablet] { display: flex; ... }
Отмечу, что
banshop-row
трансформируется в узел и итоговый стиль будет что-то наподобии[tablet][_nghost-banshop-c10] {}
Добавим логику для колонок ColumnComponent
:
Как можно увидеть, в компоненте важны тоже стили SCSS
:
@use 'sass:math';
@use 'libs/ui/stylesheets/mixins' as store-mixins;
@mixin make-columns($mode) {
&[#{$mode}] {
flex: 1 0 0;
padding: 0 1rem;
}
&[#{$mode}]:not([#{$mode}='']) {
flex: 0 0 auto;
}
:host-context(banshop-row.no-padding) &[#{$mode}] {
padding: 0;
}
@for $column from 1 through 12 {
&[#{$mode}='#{$column}'] {
width: math.percentage(math.div($column, 12));
}
}
}
:host {
display: block;
@include store-mixins.media-handset-up() {
@include make-columns(handset);
}
@include store-mixins.media-tablet-up() {
@include make-columns(tablet);
}
@include store-mixins.media-web-up() {
@include make-columns(web);
}
}
Аналогично строкам, для каждого устройства (экрана) добавляем соответствующие колонки (12 колонок, как в bootstrap).
В итоге будут стили вида:
@media (min-width: 600px) and (orientation: portrait), (min-width: 960px) and (orientation: landscape)
[banshop-column][tablet="6"] {
width: 50%;
}
[banshop-column][tablet="4"] {
width: 33.33%;
}
...
Пример использования
Создадим колонки, где на мобильном устройстве одна колонка, на планшете 2, а на пк 3.
Запустим и посмотрим:
Резюме
В данной статье разобрали решение для реализации колонок в Angular с помощью размеров из Angular CDK:
- handset — мобильное устройство
- tablet — планшет
- web — пк
Для минимизации работы с колонками и уменьшения логики в компонентах, добавили 3 директивы, с помощью которых с помощью CSS реализовали изменение стилей.
В конце привели решение и демонстрацию работы созданных колонок.
Ссылки
Все исходники находятся на github, в репозитории:
Для того, чтобы посмотреть состояние проекта на момент написания статьи, нужно выбрать соответствующий тег — layouts.
Подписывайтесь на блог, чтобы не пропустить новые статьи про Angular, и веб-разработку. Medium | Telegram| VK | FB | Tw | Inst | Ln