Skip to main content
Назад до блогу
5 хв читання

Баг, що проявився лише на iPhone SE

Чекаут, що працював на кожному пристрої, окрім 4-дюймового екрана. Як тач-таргет 44px, фіксований футер та адресна строка Safari склалися в баг, який ніхто не міг відтворити в офісі.

performanceuxcase-study

Тикетинг-платформа 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-дюймовому екрані без скролу за фіксований футер.

Чому ніхто не зловив

  1. Ні в кого в офісі не було iPhone SE. Наші тестові пристрої — iPhone 14, Pixel 7, Samsung A54. Усі з великими екранами. SE — 4.7 дюйма, значно менше сучасних телефонів.

  2. Safari DevTools не симулює динамічну панель. Коли використовуєш Safari responsive design mode на Mac, він рендерить сторінку в правильних розмірах екрана, але не симулює розгортання/згортання адресної строки. Баг невидимий у симуляторі.

  3. Відсів виглядав як поведінка користувача, а не баг. 34% конверсія виглядає як «ці користувачі не готові купувати», а не «ці користувачі фізично не можуть тапнути кнопку». Без сегментації по пристроях в аналітиці це було б невидимим.

Фікс у продакшні

Три зміни, задеплоєні в одному PR:

  1. 100vh100dvh на контейнері сторінки чекауту
  2. bottom: 0bottom: env(safe-area-inset-bottom) на фіксованому футері
  3. Лейаут Stripe Elements зі стопки на інлайн на екранах вужчих за 430px
  4. Усі тач-таргети в чекауті встановлені на min-height: 44px

Конверсія чекауту на iPhone SE зросла з 34% до 76% за перший тиждень. Все ще нижче 81% на більших iPhone — маленькі екрани завжди матимуть трохи нижчу конверсію — але відсів 44% → 11% на кроці оплати зрівнявся з кожним іншим пристроєм.

Що я перевіряю тепер

Цей баг змінив мій пре-лаунч QA-чекліст. Для кожного чекауту чи форми я тепер тестую:

  1. iPhone SE (4.7 дюйми) з розгорнутою адресною строкою Safari. Не симулятор — реальний пристрій із реальним пальцем.
  2. dvh замість vh для будь-якого повноекранного лейауту на мобілці. Динамічна панель Safari робить 100vh ненадійним.
  3. env(safe-area-inset-bottom) на кожному елементі з position: fixed. І вирізи, і панель Safari з'їдають простір знизу.
  4. Тач-таргети мінімум 44px. Не 36px, не 40px. 44px. HIG Apple існує неспроста.
  5. Лейаут Stripe Elements на вузьких екранах. Стопковий лейаут — дефолт, і він ламається на маленьких в'юпортах. Завжди тестуй на найвужчому підтримуваному пристрої.

У iPhone SE 12% частка серед наших мобільних користувачів. Це не ніша — це тисячі людей на місяць, які не могли купити квитки, бо кнопка була на 8px замалою та на 50px занизькою.


Якщо в даних конверсії видно пристроєво-специфічний відсів і ти не розумієш чому — давай розберемося разом. Іноді це одна CSS-властивість.