[Перевод] Исправление странной ошибки и стратегии отладки, проверенные временем

-kk7o7fitmyixgdho6m6dy36oxu.jpeg


Помните, когда вам в последний раз доводилось сталкиваться с ошибкой, связанной с пользовательским интерфейсом, на исправление которой у вас уходили многие часы? Возможно, эта ошибка происходила периодически, без каких-то видимых причин. Может быть, она появлялась при определённых условиях (это могло зависеть от устройства, операционной системы, браузера или от действий пользователя) или была скрыта где-то в недрах одной из множества фронтенд-технологий, являющихся частью клиентской части веб-проекта?

Недавно мне пришлось вспомнить о том, какими запутанными могут быть причины возникновения ошибок пользовательских интерфейсов. А именно, речь идёт об исправлении интересной ошибки, влияющей на вывод SVG-изображений в браузере Safari. Эта ошибка возникала без какой-то определённой системы и без каких-то очевидных причин. Я, столкнувшись с проблемой, попытался найти похожие случаи, надеясь на то, что описания таких случаев дадут мне намёк на то, что происходит. Но мне не удалось отыскать ничего полезного. Правда, несмотря на все стоящие передо мной препятствия, я смог с этой ошибкой справиться.

Я проанализировал проблему, используя некоторые стратегии отладки, о которых я собираюсь рассказать в этой статье. После того, как от ошибки я избавился, я вспомнил совет, который Крис Койер дал читателям своего Твиттера несколько лет назад. Этот совет звучит так: «Напишите статью, которую вы хотели бы найти, когда обращались к поисковику». Собственно говоря, так я и поступил.

Обзор проблемы


В проекте, над которым я работал, на действующем сайте, я нашёл ошибку, проявление которой записал на этом видео. Вот как выглядит кнопка в нормальном состоянии.

e688004121318ec59625546f6fc9a674.png


Кнопка в нормальном состоянии

А вот — та же кнопка после возникновения проблемы.

45468e3c40b43fcd79901145b2d6609d.png


Часть кнопки обрезана

Я воспроизводил эту ошибку в различных ситуациях, вызывающих перерисовку страницы. Например, она возникала при изменении размеров окна браузера.

Для того чтоб продемонстрировать проблему, я создал пример на CodePen. Подробнее его мы обсудим ниже. Но вы можете самостоятельно с этим примером поэкспериментировать. А именно, речь идёт о том, что если открыть этот пример в браузере Safari, то, при загрузке страницы, кнопки будут выглядеть так, как ожидается. Но если щёлкнуть по одной из двух более крупных кнопок, ошибка высунет свою уродливую голову.

afdf5c13eb4d7e0e281ebb86da0dcc72.png


Почему SVG-изображение оказывается обрезанным?

Каждый раз, когда происходит событие paint, SVG-изображения, используемые в более крупных кнопках, выводятся неправильно. Эти изображения просто подвергаются обрезке. Это может происходить, без видимых причин, при загрузке страницы. Это может случиться даже при изменении размеров окна. В общем, ошибка появляется в самых разных ситуациях.

Обзор проекта, в котором происходила ошибка


Я так думаю, что, рассказывая об ошибке, хорошо будет раскрыть подробности о проекте и об условиях, в которых она происходит.

  • В проекте используется React (но читателю этой статьи необязательно знать React для того чтобы в ней разобраться).
  • SVG-изображения импортируются в проект в виде React-компонентов и встраиваются в HTML средствами webpack.
  • Изображения экспортируются из дизайнерской программы. В их коде нет синтаксических ошибок.
  • Изображения стилизуются средствами CSS.
  • Изображения, которые выводятся с ошибкой, расположены внутри HTML-элемента
  • Проблема появляется только в браузере Safari (она была замечена в его 13 версии).


Исследование ошибки


Давайте рассмотрим ошибку и поразмыслим о том, можно ли сделать какие-то предположения относительно того, что происходит. Причины подобных ошибок обычно не лежат где-то на поверхности, поэтому, столкнувшись с такими ошибками, нельзя сразу с уверенностью сказать о том, что происходит. Предпринимая первую попытку разобраться в проблеме, мы не обязаны стремиться к выявлению её причины со 100% точностью. Мы будем исследовать ошибку пошагово, формулируя и проверяя гипотезы, которые помогут нам сузить список возможных причин происходящего.

Формулирование гипотезы


Происходящее, на первый взгляд, выглядит как ошибка CSS. Возможно, при наведении указателя мыши на кнопку к ней применяются какие-то стили, которые и ломают макет. Возможно, во всём виноват атрибут overflow SVG-изображения. Кроме того, возникает такое ощущение, что ошибка происходит без какой-то определённой системы при перерисовке страницы по разным поводам (событие paint при изменении размеров окна браузера, при наведении указателя мыши на кнопку, при щелчке по ней и так далее).

Начнём с самого простого и очевидного предположения. Представим, что ошибка кроется в CSS. Мы можем исходить из предположения о том, что в браузере Safari есть ошибка, которая приводит к неправильному выводу SVG-изображений при применении к SVG-элементам каких-то специфических стилей. Например, вроде тех стилей, что используются для построения flex-макетов.

Только что мы сформулировали гипотезу. Нашим следующим шагом будет проведение испытания, которое либо подтвердит, либо опровергнет эту гипотезу. Результат каждого испытания даст нам новые сведения об ошибке и поможет в формулировании следующих гипотез.

Упрощение проблемы


Мы будем пользоваться стратегией отладки, которая называется «упрощение проблемы». Это позволит нам точно определить место возникновения ошибки. В одной лекции по информатике Корнеллского университета эту стратегию описывают как «подход по постепенному избавлению от кода, который не имеет отношения к ошибке».

Исходя из предположения о том, что ошибка кроется в CSS, мы можем, в итоге, или найти причину ошибки, или исключить из уравнения CSS, что уменьшит количество возможных причин возникновения ошибки и снизит сложность проблемы.

Давайте испытаем нашу гипотезу. Попытаемся её подтвердить. В таком случае, если временно отключить от страницы все стили, не являющиеся стандартными, это должно привести к тому, что ошибка появляться перестанет.

Вот код, с помощью которого подключается соответствующий файл стилей:

import 'css/app.css';


Я, для демонстрации вывода элементов без CSS, создал этот CodePen-проект. В React SVG-графика импортируется в проект в виде компонента, потом соответствующий код встраивается в HTML с помощью webpack.

5561da73db32b676a59346e5625ead07.png


Обычный вид кнопок

Если открыть вышеупомянутый проект в Safari и щёлкнуть по одной из крупных кнопок, то окажется, что ошибка никуда не делась. Она происходит и при загрузке страницы, но при использовании CodePen для вызова ошибки нужно щёлкнуть по кнопке.

6833b3da1e4b1b10200b151b6e7e9565.png


Ошибка никуда не делась и при отключении CSS (Safari 13)

В результате мы можем сделать вывод о том, что CSS тут ни при чём. Правда, мы можем обратить внимание на то, что в таких условиях неправильно выводятся только две из пяти кнопок. Запомним это и перейдём к следующей гипотезе.

Изоляция ошибки


Наша следующая гипотеза заключается в том, что в Safari есть ошибка, возникающая при выводе SVG-изображений внутри HTML-элементов