Дизайн Telegram Mini App: тема, кнопки и нативное ощущение
Практика4 минРедакция Innovialabs
Коротко
Mini App ощущается нативным, когда берёт цвета из темы Telegram, учитывает safe areas, использует MainButton и BackButton вместо своих кнопок, даёт тактильный отклик и открывается почти мгновенно.
Что делает Mini App нативным
Пользователь не должен замечать, что открыл сайт. Для этого Mini App:
- берёт цвета из темы Telegram, а не из своего брендбука целиком;
- учитывает размер окна и safe areas — вырезы, системные панели, кнопки Telegram;
- использует системные кнопки — MainButton, BackButton, SettingsButton;
- отвечает вибрацией на важные действия;
- загружается быстро и сразу вызывает
Telegram.WebApp.ready().
Всё это даёт объект window.Telegram.WebApp из официального скрипта telegram-web-app.js.
Цвета темы
Telegram передаёт в приложение themeParams — набор цветов текущей темы пользователя: bg_color, text_color, hint_color, link_color, button_color, button_text_color, secondary_bg_color и другие. Они же доступны как CSS-переменные.
body {
background: var(--tg-theme-bg-color);
color: var(--tg-theme-text-color);
}
.card { background: var(--tg-theme-secondary-bg-color); }
.hint { color: var(--tg-theme-hint-color); }
Практические правила:
- Фон, текст и подсказки — только из темы. Иначе в тёмной теме будет белое пятно.
- Бренд оставьте в акцентах: логотип, иллюстрации, одна-две фирменные плашки.
- Подпишитесь на событие
themeChanged— пользователь может сменить тему, не закрывая приложение. - Цвет шапки и фона окна задаются через
setHeaderColor()иsetBackgroundColor()— подберите их под первый экран, чтобы не было «шва». - Всегда задавайте запасные значения для CSS-переменных: при открытии в обычном браузере темы нет.
Viewport и safe areas
Высота окна Mini App меняется: пользователь тянет шторку, открывается клавиатура. Поэтому 100vh здесь ненадёжен.
--tg-viewport-height— текущая высота, меняется во время анимации.--tg-viewport-stable-height— высота после завершения изменений. Используйте её для элементов, прибитых к низу.expand()раскрывает окно на максимальную высоту — вызывайте, если интерфейсу тесно.
Safe areas — зоны, которые перекрывают системные элементы устройства и интерфейс Telegram. Есть два набора отступов:
--tg-safe-area-inset-*— от системных элементов (вырез, жестовая полоса);--tg-content-safe-area-inset-*— от элементов Telegram поверх контента.
.screen {
padding-top: calc(var(--tg-safe-area-inset-top, 0px) + var(--tg-content-safe-area-inset-top, 0px));
padding-bottom: var(--tg-safe-area-inset-bottom, 0px);
}
Особенно важно в полноэкранном режиме: без отступов заголовок уйдёт под вырез камеры.
Кнопки: MainButton и BackButton
MainButton — большая кнопка внизу экрана в стиле Telegram. Её стоит использовать для главного действия экрана: «Оформить заказ», «Оплатить», «Далее».
const tg = window.Telegram.WebApp;
tg.MainButton.setParams({ text: "Оформить заказ", is_visible: true });
tg.MainButton.onClick(async () => {
tg.MainButton.showProgress();
await submitOrder();
tg.MainButton.hideProgress();
});
- Одно главное действие на экран. Для второстепенного есть
SecondaryButton. - Отключайте кнопку (
disable()), пока форма не заполнена, и показывайтеshowProgress()на время запроса. - BackButton в шапке вместо своей стрелки «назад». Связывайте её с роутером приложения.
- Не дублируйте MainButton своей кнопкой в вёрстке — получится две одинаковые кнопки.
- Снимайте обработчики через
offClick()при смене экрана, иначе клик сработает несколько раз.
Тактильный отклик
HapticFeedback делает интерфейс «физическим»:
impactOccurred("light" | "medium" | "heavy" | "rigid" | "soft")— нажатия и перетаскивания;notificationOccurred("success" | "warning" | "error")— результат действия;selectionChanged()— смена выбора в списке или переключателе.
Используйте вибрацию дозированно: на подтверждения, ошибки и выбор. Вибрация на каждый тап утомляет.
Полноэкранный режим
requestFullscreen() разворачивает Mini App на весь экран — подходит для игр, медиа, карт. Учитывайте:
- обязательны safe areas, иначе контент окажется под системными элементами;
- слушайте
fullscreenChangedиfullscreenFailed— режим поддерживается не во всех клиентах; - для обычных магазинов и форм полноэкранный режим чаще не нужен.
Если в приложении есть вертикальные жесты (свайпы, слайдеры), disableVerticalSwipes() не даст случайно свернуть окно.
Быстрая загрузка
Первое впечатление — это скорость. Чек-лист:
- вызывайте
ready()как можно раньше, после отрисовки первого экрана; - показывайте скелетон в цветах темы, а не пустой белый экран;
- держите стартовый бандл маленьким, тяжёлые экраны грузите лениво;
- раздавайте статику через CDN с кешированием;
- не блокируйте первый экран запросами к API — сначала каркас, потом данные;
- проверяйте на недорогом Android и медленной сети, а не только на своём ноутбуке.
Частые ошибки
- Жёстко заданный белый фон и тёмный текст.
100vhи фиксированные блоки, которые прыгают при открытии клавиатуры.- Своя кнопка «Назад» в углу вместо BackButton.
- Отсутствие проверки версии: перед вызовом новых методов используйте
isVersionAtLeast().