Тикетинг-платформа E7 була в продакшні два місяці. Конверсія чекауту: 78% по всіх мобільних пристроях. Добре, не відмінно, але в межах індустріальних бенчмарків.
Потім я сегментував по пристроях. iPhone 13/14/15: 81%. Pixel серія: 79%. Samsung Galaxy S серія: 77%. iPhone SE (2-ге та 3-тє покоління): 34%.
Тридцять чотири відсотки. Половина конверсії кожного іншого пристрою. На пристрої, який носили 12% наших мобільних користувачів.
Пошук
Дані казали що, але не де. Воронка чекауту мала 4 кроки: вибір місць → огляд кошика → дані оплати → підтвердження. Мені потрібно було зрозуміти, на якому кроці витікають.
Розбивка воронки для iPhone SE:
| Крок | Відсів (iPhone SE) | Відсів (усі мобільні) |
|---|---|---|
| Вибір місць → Огляд кошика | 8% | 6% |
| Огляд кошика → Дані оплати | 14% | 5% |
| Дані оплати → Підтвердження | 44% | 11% |
| Загальна відмова | 66% | 22% |
Катастрофа була на кроці 3 → 4. 44% користувачів iPhone SE, які дійшли до форми оплати, ніколи не завершували платіж. На кожному іншому пристрої — 11%.
Відтворення
Взяв тестовий iPhone SE (3-тє покоління, 4.7-дюймовий екран, iOS 17). Відкрив чекаут. Обрав місця. Переглянув кошик. Натиснув «Перейти до оплати».
Форма оплати завантажилася. Stripe Elements відрендерив поля картки. Все виглядало нормально.
Потім спробував натиснути «Сплатити €45.00».
Кнопка була видна. Але коли я тапнув — нічого. Тапнув знову. Нічого. Прокрутив вниз — кнопка пішла вгору. Прокрутив вгору — кнопка пішла вниз. Вона тікала від пальця.
Тоді помітив: адресна строка Safari була в розгорнутому стані. На 4.7-дюймовому екрані це краде близько 50px висоти в'юпорту. Кнопка оплати була в position: fixed футері, позиціонованому на bottom: 0 — але розгорнута адресна строка Safari зсунула візуальний в'юпорт вгору, і кнопка рендерилася за нижньою панеллю інструментів Safari.
Піраміда з трьох багів
Це був не один баг. Їх було три, накладених один на одного:
Баг 1: Фіксований футер і динамічний в'юпорт Safari
Кнопка оплати жила у фіксованому футері:
.checkout-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 16px;
}
На великих екранах це працює. На iPhone SE з розгорнутою адресною строкою Safari bottom: 0 означає «низ layout viewport» — який знаходиться за панеллю інструментів Safari. Кнопка рендериться, але нетапабельна, бо UI браузера її закриває.
Фікс: Замінити bottom: 0 на bottom: env(safe-area-inset-bottom) та переключитися з 100vh на 100dvh (dynamic viewport height) для контейнера сторінки. dvh враховує динамічну панель Safari.
.checkout-footer {
position: fixed;
bottom: env(safe-area-inset-bottom, 0px);
left: 0;
right: 0;
padding: 16px;
}
.checkout-page {
min-height: 100dvh;
}
Баг 2: Тач-таргет був занадто малим
Навіть після фіксу в'юпорту кнопку було важко тапнути на 4-дюймовому екрані. Кнопка «Сплатити» була 36px заввишки — нижче рекомендованого Apple мінімуму в 44px для тач-таргетів. На 14 Pro 36px нормально, бо екран великий. На SE кожен піксель тач-таргету критичний.
Фікс: Збільшив висоту кнопки до 48px та додав min-height: 44px до всіх інтерактивних елементів у чекауті.
Баг 3: Stripe Elements рендерилися за екраном
Поля введення картки Stripe (номер картки, термін дії, CVC) — це iframe. На маленькому екрані три поля стояли вертикальною стопкою, штовхаючи загальну висоту форми за межі в'юпорту. Користувачу потрібно було скролити, щоб побачити поле CVC, але фіксований футер закривав низ скролованої області, і поле CVC було частково сховане за кнопкою «Сплатити».
Користувачі вводили номер картки та термін дії, потім не могли побачити поле CVC, потім не могли знайти кнопку відправки, потім йшли.
Фікс: Змінив лейаут Stripe Elements зі стопки на інлайн (номер картки в один рядок, термін дії + CVC у другий). Це зменшило висоту форми достатньо, щоб усе поміщалося в в'юпорт на 4.7-дюймовому екрані без скролу за фіксований футер.
Чому ніхто не зловив
-
Ні в кого в офісі не було iPhone SE. Наші тестові пристрої — iPhone 14, Pixel 7, Samsung A54. Усі з великими екранами. SE — 4.7 дюйма, значно менше сучасних телефонів.
-
Safari DevTools не симулює динамічну панель. Коли використовуєш Safari responsive design mode на Mac, він рендерить сторінку в правильних розмірах екрана, але не симулює розгортання/згортання адресної строки. Баг невидимий у симуляторі.
-
Відсів виглядав як поведінка користувача, а не баг. 34% конверсія виглядає як «ці користувачі не готові купувати», а не «ці користувачі фізично не можуть тапнути кнопку». Без сегментації по пристроях в аналітиці це було б невидимим.
Фікс у продакшні
Три зміни, задеплоєні в одному PR:
100vh→100dvhна контейнері сторінки чекаутуbottom: 0→bottom: env(safe-area-inset-bottom)на фіксованому футері- Лейаут Stripe Elements зі стопки на інлайн на екранах вужчих за 430px
- Усі тач-таргети в чекауті встановлені на
min-height: 44px
Конверсія чекауту на iPhone SE зросла з 34% до 76% за перший тиждень. Все ще нижче 81% на більших iPhone — маленькі екрани завжди матимуть трохи нижчу конверсію — але відсів 44% → 11% на кроці оплати зрівнявся з кожним іншим пристроєм.
Що я перевіряю тепер
Цей баг змінив мій пре-лаунч QA-чекліст. Для кожного чекауту чи форми я тепер тестую:
- iPhone SE (4.7 дюйми) з розгорнутою адресною строкою Safari. Не симулятор — реальний пристрій із реальним пальцем.
dvhзамістьvhдля будь-якого повноекранного лейауту на мобілці. Динамічна панель Safari робить100vhненадійним.env(safe-area-inset-bottom)на кожному елементі зposition: fixed. І вирізи, і панель Safari з'їдають простір знизу.- Тач-таргети мінімум 44px. Не 36px, не 40px. 44px. HIG Apple існує неспроста.
- Лейаут Stripe Elements на вузьких екранах. Стопковий лейаут — дефолт, і він ламається на маленьких в'юпортах. Завжди тестуй на найвужчому підтримуваному пристрої.
У iPhone SE 12% частка серед наших мобільних користувачів. Це не ніша — це тисячі людей на місяць, які не могли купити квитки, бо кнопка була на 8px замалою та на 50px занизькою.
Якщо в даних конверсії видно пристроєво-специфічний відсів і ти не розумієш чому — давай розберемося разом. Іноді це одна CSS-властивість.