Назад к блогу
8 мин. чтения

От Figma до готового сайта: где ломается адаптив?

Дизайнер рисует 3 фрейма, а сайт у пользователя работает в диапазоне ширин. Разбираем, почему адаптив ломается между брейкпоинтами и при чём тут viewport.
Содержание
  1. Три фрейма — не полный адаптив
  2. Viewport — ключ к пониманию
  3. Брейкпоинты задают диапазоны, а не точки
  4. Фиксированные размеры — это не зло. Зло — когда за ними нет логики!
  5. Ключевые выводы

Три фрейма — не полный адаптив

Дизайнер сделал три фрейма: десктоп, планшет, смартфон. Для примера: 1440, 768, 375. Вроде всё — адаптив закрыт, можно отдавать в разработку или верстать в конструкторе. А часто делают и вовсе два — десктоп и телефон, а что между ними, как будто неважно.

Пользователь открывает сайт на десктопе (ноутбуке) — но не на весь экран, а в окне на половину. Или просто тянет браузер за угол либо меняет масштаб, подгоняя под себя, как удобно ему. И где-то между тремя ширинами layout едет: блоки наезжают, текст вылезает, кнопка «убегает» за край.

И это не только про десктоп. Открой такой сайт на планшете или на каком-нибудь другом устройстве — и увидишь одно из двух. Либо layout ломается, потому что эта ширина в промежутке значений, который никто не проработал. Либо в средний формат «вписана» десктопная версия — всё на месте, но шрифты и элементы мелкие до нечитаемости, потому что десктопный фрейм пропорционально ужали до размеров планшета. Вариантов, почему у пользователя отличается размер окна, может быть масса: небольшой ноутбук, увеличенный масштаб и так далее! Смысл в том, что мы заранее не знаем, на каком устройстве и при каких настройках пользователь будет смотреть сайт!

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

Это первый и самый важный сдвиг в мышлении, без которого дизайн и разработка не будут качественными!

Viewport — ключ к пониманию

Когда дизайнер говорит «делаю экран на 1440», он имеет в виду размер фрейма в Figma. И наверняка подразумевает «разрешение» — этот термин ходит по сообществам, но далеко не каждый повторяет его с реальным пониманием.

Разрешение — это физическое свойство матрицы дисплея. И важно понимать: масштабирование, которое пользователь выставляет в операционной системе (Windows, macOS, Linux) как удобно ему — меняет размер пространства, в котором работают все приложения и браузер — в их числе.

Viewport — это видимая область окна браузера, в которой рендерится вёрстка. Окно, которое пользователь меняет как ему удобно: разворачивает на весь экран или уменьшает, тянет за угол, держит браузер рядом с другим окном на половину или две трети монитора, применяет браузерный зум. Это паттерны просмотра на десктопе. Каждое такое движение меняет viewport мгновенно — страница ререндерится в реальном времени.

На мобильных устройствах такой свободы менять размер окна нет — но само разнообразие устройств задаёт то же требование: вёрстка должна работать в достаточно широком диапазоне. По современным веб-стандартам до сих пор поддерживается минимальная ширина 320 пикселей. А максимальная фактически не ограничена — достаточно посмотреть на широкоформатные и ультраширокие мониторы.

У viewport есть прямое доказательство, оно лежит в HTML-коде буквально каждого сайта:

<meta name=«viewport» content=«width=device-width, initial-scale=1»>

Этот тег стоит по умолчанию в любой современной реализации и в каждом конструкторе — Tilda, Webflow содержат его из коробки. Он говорит браузеру: бери реальную ширину окна просмотра — того самого viewport.1 Именно viewport, а не «разрешение» матрицы дисплея и не размер фрейма и есть та величина, в которой реально отрисовывается layout.2

Брейкпоинты задают диапазоны, а не точки

Брейкпоинты срабатывают от ширины viewport, а не от ширины экрана и не от «разрешения». Когда ты пишешь @media (max-width: 768px) — или работаешь в конструкторе, где брейкпоинты проставлены уже за тебя — браузер сравнивает 768 не с диагональю матрицы и не с числом из характеристик устройства, а с шириной того самого окна просмотра, которое пользователь меняет ресайзом и зумом в реальном времени.3 Под капотом конструктора, в коде те же @media, просто написанные не твоей рукой и срабатывают они всё от того же viewport.

Диапазоны. Здесь прячется вторая ловушка. Кажется, что 768px — это граница, на которой меняется фрейм: до 768 одна вёрстка, после — другая. Будто есть только три стабильных состояния (которые в Figma) и достаточно «нарисовать» каждое.

На самом деле есть интервалы: от 1440 до 768, 768–375, 375–320. (В конструкторах или иных системах эти интервалы могут быть другими!) Но общий смысл: перекрыть весь диапазон от 320px и выше. Три фрейма из Figma — это всего лишь три «скриншота» из всего диапазона состояний. А пользователь не обязан открывать ровно ту ширину, которую вы отрисовали и отверстали.

Для пользователей важен весь диапазон, внутри которого layout должен работать. От 1440 до 768 — это не одно «планшетное состояние», это сотни возможных промежуточных ширин с шагом 1px. И на каждой страница обязана выглядеть нормально.

Фрейм в Figma показывает, как layout выглядит на одной конкретной ширине. Но за кадром то, как он себя ведёт при переходе от одной ширины к другой. Это статичный снимок одного состояния. Несколько таких снимков не описывают переходы между ними — а проблемы возникают как раз в тех промежутках, которые никто не «отрисовал» и не тестировал.

Фиксированные размеры — это не зло. Зло — когда за ними нет логики!

1440, 768, 375 — сами по себе нормальные числа. Проблема не в них, а в том, понимает ли дизайнер, как layout будет работать в промежуточных размерах.

Если макет спроектирован и собран грамотно — применён autolayout (flex и grid), у блоков выставлены min-max размеры, а дизайнер понимает работу адаптивной вёрстки или работает в связке с разработчиком с обратной связью на итерациях, — то трёх-четырёх фреймов, а иногда и двух, достаточно. Разработчик выстроит поведение, потому что логика уже заложена в макет.

Если же числа взяты из головы или «так сказали на курсах», а сам дизайн нелогичен — результат будет тем хуже, чем дальше реальные размеры окна браузера пользователя от размеров нарисованного фрейма. И этих «дальше» — много: масштабирование в ОС, параметры браузера и т. д. Поэтому реальный размер viewport в стандартное значение попадает далеко не всегда. (Как характеристики железа превращаются в разные числа в софте — большая тема, разберём это в следующих постах).

С высотой тоже показательно. В Figma рисуют на один экран — условные 900px сверху донизу. А в жизни сверху поджимает адресная строка браузера, снизу системная панель, а на телефоне ещё и плавающие панели, которые прячутся и появляются при скролле. Реального места под контент бывает и меньше, и больше, чем в статичном макете, — и на мобильных высота viewport меняется прямо во время скролла. Так что даже если ширина реального окна просмотра случайно совпала с отрисованным фреймом — высота скорее всего будет отличаться.

Ключевые выводы

  1. Сайт на стороне пользователя работает в диапазоне, а не в фиксированных размерах фреймов. Не 2–3–4 фиксированные ширины — а любая ширина из непрерывного диапазона.
  2. Брейкпоинты задают интервалы, и важен весь диапазон. Между 768 и 1440 сотни возможных ширин, и на каждой страница должна работать! Так же и во всём диапазоне от 320px и выше.
  3. Фрейм — это статичный снимок одного состояния. Он показывает, как layout выглядит на одной ширине, но молчит о поведении между ширинами. А ломается всё именно в нестандартных значениях, которые не проработаны и не протестированы.
  4. Брейкпоинт включается от размера viewport. Доказательство — meta viewport tag в коде каждого сайта. Именно от размера viewport отрисовывается layout, а на размер влияют несколько разных параметров, которые пользователь в полном праве менять под себя.
  5. Фиксированные размеры фреймов не проблема — проблема, когда за ними нет логики поведения. Качественный дизайн эту логику несёт: autolayout (flex и grid) и min-max размеры заставляют блоки перестраиваться и в заданном интервале менять размеры под viewport, поэтому на промежуточных ширинах ничего не ломается. А когда логика заложена, хватает и трёх-четырёх фреймов.
  6. Высота viewport тоже меняется — и довольно сильно. Задай минимальную высоту, на которой ничего не ломается: если места меньше, обычный скролл это решает — и это нормально. И продумай обратный случай, когда высоты много (например, планшет в вертикальной ориентации): жёстко заданный 100vh здесь может раздуть блок и оставить избыток пустого пространства.
  7. Вывод для двух ролей. Дизайнеру — надо проектировать: понимать, как вёрстка адаптируется между размерами и применять логику на этапе дизайна, а не рисовать статичные картинки. Разработчику — вёрстка должна поддерживать весь диапазон, а не набор застывших состояний.

Ссылки

  1. MDN — «<meta name="viewport">» — референс тега, откуда берутся те самые ~980px без него и почему width=device-width — правильное значение.

  2. MDN — «Viewport concepts» — что такое viewport, чем layout viewport отличается от visual, почему это не то же самое, что экран.

  3. MDN — «Using media queries» — что именно меряет @media: ширину viewport, а не устройства (различие width и device-width).