
Привет, Хабр! Меня зовут Светлана Моторкина, я Head of Design в компании Friflex. В этой статье расскажу, как мы придумали формулу, чтобы управлять сложными адаптивными интерфейсами с большим количеством повторяющихся элементов в ряду.
Если вы работаете с плотными интерфейсами вроде канбан-досок, галерей, календарей, игровых сеток, другими сложными адаптивами, этот подход поможет сократить количество макетов и сделать отображение предсказуемым.
Один из наших продуктов — idChess, платформа для распознавания и трансляции шахматных партий в реальном времени. В ней есть функция проведения турниров: организаторы задают параметры трансляции, а зрители могут следить за игрой, анализировать позиции, прогнозировать ходы и болеть за участников.
В турнирной сетке может быть от одной до двенадцати досок в ряд, и на каждой есть имена игроков, часы, фигурки. Экран можно сжимать как угодно: на четверть, на половину, никак, и все должно отображаться корректно.
Разработчики не понимали, как должны вести себя элементы. Куда уезжают имена игроков, что происходит с часами, почему фигуры на маленьких экранах превращаются в пиксели. На некоторых размерах все становилось настолько мелким, что просто ничего не было видно.
Стандартный подход нам не подходил
Стандартная практика включает отрисовку нескольких версий каждого экрана для ключевых контрольных точек (breakpoints). Чаще всего это три состояния:
мобильное (320–480 px);
планшетное (768–1024 px);
десктопное (1440 px и выше).
Количество макетов зависит от сложности интерфейса и числа уникальных экранов. Для одного экрана дизайнер может подготовить 3–5 версий, чтобы учесть все состояния и элементы, которые меняются в зависимости от ширины экрана.
Мы пытались действовать по классике: отрисовать мобильную, планшетную и десктопную версии экрана. Быстро выяснилось, что этого недостаточно. При любом нестандартном размере экрана или изменении количества досок макеты переставали работать. Состояний становилось так много, что управлять ими было невозможно.

Формула
Мы отказались от жестко заданных макетов и перешли к расчетному подходу. Взяли фактическую ширину окна браузера (r) и вычли из нее отступы от краев экрана (2d). Затем из оставшегося пространства убрали суммарную ширину промежутков между досками (q × d’), где q всегда на один меньше, чем количество досок в строке (n − 1). Полученное значение поделили на количество досок (n) и получили ширину одной доски (a).
В формуле это выглядит так: a = (r − 2d − q × d’) / n.
На первом этапе формула считала именно ширину доски. Позже, когда столкнулись с проблемами вроде плотности пикселей, мы изменили подход: теперь формула считает размер доски в более широком смысле, а потом мы сопоставляем его с карточкой, в которой прописаны размеры всех элементов.
Ограничения и пресеты
С формулой стало больше порядка. Но полная свобода выбора количества досок снова вносила хаос. Раньше можно было поставить любое значение от 1 до 12, и предсказать поведение интерфейса было сложно. Поэтому мы ввели ограничения: для каждого диапазона ширины экрана фиксировали только несколько допустимых вариантов. Например, при ширине от 720 до 1023 px можно выбрать только 4 или 5 досок.
Вообще мы ввели ограничения по трем причинам: чтобы доски не были слишком мелкими на маленьком экране, чтобы интерфейс не менялся хаотично при каждом пикселе ресайза и чтобы заранее знать, какие варианты отображения доступны.
Количество досок определили через тестирование и реальную работу интерфейса:
Мобильные устройства: 1–2 доски.
Планшеты: 3–4 досок.
Десктопы: 5–8 досок.
Ультраширокие мониторы: 9 и более.
Эти значения легли в основу пресетов. Мы разбили экраны на диапазоны (брейкпоинты) и для каждого определили свои отступы (d и d’), количество досок (n). Все это объединили в наборы настроек, которые можно применять без ручной подгонки параметров.

Как это работает, на примере
Берем ширину окна — например, 1123 px.
Смотрим в пресетах: для этой ширины доступно 3–6 досок. Берем оптимальное значение, например 5.

Вычисляем ширину доски по формуле. Получаем 202.2 px и округляем до 202 px
a = (r − 2d − q × d’) / n
n = 5
r = 1123
d = 24
d' = 16
q = 4
a = (1123 - (2*24) - (4*16)) / 5
a = 202.2 px
Сопоставляем ширину с карточками.

Получаем параметры для всех элементов.

Итог
У нас получилось заменить десятки макетов связкой формула плюс фиксированные диапазоны плюс пресеты. Интерфейс предсказуемо перестраивается под любое устройство и количество досок, команда работает с конечным набором вариантов, а не с бесконечной матрицей состояний.
Это все. Надеюсь, наш опыт будет вам полезен. Такой подход — по сути способ управлять плотностью элементов в ограниченном пространстве без бесконечной отрисовки макетов. Мне кажется, он отлично ложится на разные сценарии, где элементов много, они повторяются по структуре, а их количество меняется динамически. Например, в фотогалереях, дашбордах и игровых интерфейсах.