Три фрейма — не полный адаптив
Дизайнер сделал три фрейма: десктоп, планшет, смартфон. Для примера: 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 меняется прямо во время скролла. Так что даже если ширина реального окна просмотра случайно совпала с отрисованным фреймом — высота скорее всего будет отличаться.
Ключевые выводы
- Сайт на стороне пользователя работает в диапазоне, а не в фиксированных размерах фреймов. Не 2–3–4 фиксированные ширины — а любая ширина из непрерывного диапазона.
- Брейкпоинты задают интервалы, и важен весь диапазон. Между 768 и 1440 сотни возможных ширин, и на каждой страница должна работать! Так же и во всём диапазоне от 320px и выше.
- Фрейм — это статичный снимок одного состояния. Он показывает, как layout выглядит на одной ширине, но молчит о поведении между ширинами. А ломается всё именно в нестандартных значениях, которые не проработаны и не протестированы.
- Брейкпоинт включается от размера viewport. Доказательство — meta viewport tag в коде каждого сайта. Именно от размера viewport отрисовывается layout, а на размер влияют несколько разных параметров, которые пользователь в полном праве менять под себя.
- Фиксированные размеры фреймов не проблема — проблема, когда за ними нет логики поведения. Качественный дизайн эту логику несёт: autolayout (flex и grid) и min-max размеры заставляют блоки перестраиваться и в заданном интервале менять размеры под viewport, поэтому на промежуточных ширинах ничего не ломается. А когда логика заложена, хватает и трёх-четырёх фреймов.
- Высота viewport тоже меняется — и довольно сильно. Задай минимальную высоту, на которой ничего не ломается: если места меньше, обычный скролл это решает — и это нормально. И продумай обратный случай, когда высоты много (например, планшет в вертикальной ориентации): жёстко заданный
100vhздесь может раздуть блок и оставить избыток пустого пространства. - Вывод для двух ролей. Дизайнеру — надо проектировать: понимать, как вёрстка адаптируется между размерами и применять логику на этапе дизайна, а не рисовать статичные картинки. Разработчику — вёрстка должна поддерживать весь диапазон, а не набор застывших состояний.
Ссылки
-
MDN — «
<meta name="viewport">» — референс тега, откуда берутся те самые ~980px без него и почемуwidth=device-width— правильное значение. ↩ -
MDN — «Viewport concepts» — что такое viewport, чем layout viewport отличается от visual, почему это не то же самое, что экран. ↩
-
MDN — «Using media queries» — что именно меряет
@media: ширину viewport, а не устройства (различиеwidthиdevice-width). ↩