
Erinnerst du dich an das letzte Mal, als du auf einen UI-Fehler gestoßen bist, dessen Behebung Stunden und Stunden gedauert hat? Möglicherweise trat dieser Fehler regelmäßig ohne ersichtlichen Grund auf. Vielleicht erschien es unter bestimmten Bedingungen (es könnte vom Gerät, Betriebssystem, Browser oder Benutzeraktionen abhängen) oder war es irgendwo in den Tiefen einer der vielen Front-End-Technologien versteckt, die Teil der Client-Seite des Webprojekts sind?
Ich musste mich kürzlich daran erinnern, wie verwirrend die Ursachen von UI-Fehlern sein können. Wir sprechen nämlich über die Behebung eines interessanten Fehlers, der sich auf die Ausgabe von SVG-Bildern im Safari-Browser auswirkt. Dieser Fehler trat ohne ein bestimmtes System und ohne offensichtlichen Grund auf. Als ich mit einem Problem konfrontiert wurde, versuchte ich, ähnliche Fälle zu finden, in der Hoffnung, dass Beschreibungen solcher Fälle mir einen Hinweis darauf geben würden, was geschah. Aber ich konnte nichts Nützliches finden. Trotz aller Hindernisse vor mir konnte ich diesen Fehler zwar bewältigen.
Ich habe das Problem mit einigen der Debugging-Strategien analysiert, die ich in diesem Artikel behandeln werde. Nachdem ich den Fehler beseitigt hatte, erinnerte ich mich an den Ratwas Chris Coyer vor einigen Jahren seinen Twitter-Lesern gab. Dieser Rat lautet wie folgt: "Schreiben Sie den Artikel, den Sie beim Besuch einer Suchmaschine finden möchten." Genau das habe ich getan.
Problemübersicht
In einem Projekt, an dem ich gearbeitet habe, habe ich auf einer Live-Site einen Fehler gefunden, dessen Manifestation ich in diesem Video aufgezeichnet habe . So sieht die Schaltfläche im Normalzustand aus.

Taste im Normalzustand
Und hier ist die gleiche Taste nach einem Problem.

Ein Teil der Schaltfläche ist abgeschnitten.
Ich habe diesen Fehler in verschiedenen Situationen reproduziert, wodurch die Seite neu gezeichnet wurde. Beispielsweise trat es auf, wenn die Größe des Browserfensters geändert wurde.
Um das Problem zu demonstrieren, habe ich ein Beispiel für CodePen erstellt . Wir werden es weiter unten genauer diskutieren. Mit diesem Beispiel können Sie jedoch selbst experimentieren. Wir sprechen nämlich von der Tatsache, dass die Schaltflächen beim Laden der Seite wie erwartet aussehen, wenn Sie dieses Beispiel im Safari-Browser öffnen. Wenn Sie jedoch auf eine der beiden größeren Schaltflächen klicken, ragt der Fehler aus seinem hässlichen Kopf heraus.

Warum wird das SVG-Bild zugeschnitten?
Jedes Mal, wenn das Ereignis eintritt
paint, werden die in den größeren Schaltflächen verwendeten SVG-Bilder nicht korrekt angezeigt. Diese Bilder werden einfach zugeschnitten. Dies kann ohne ersichtlichen Grund beim Laden der Seite passieren. Dies kann auch dann passieren, wenn die Fenstergröße geändert wird. Im Allgemeinen tritt der Fehler in verschiedenen Situationen auf.
Eine Übersicht über das Projekt, in dem der Fehler aufgetreten ist
Ich denke, wenn wir über den Fehler sprechen, wäre es gut, Details über das Projekt und die Bedingungen, unter denen es auftritt, preiszugeben.
- Das Projekt verwendet React (aber der Leser dieses Artikels muss React nicht kennen, um es zu verstehen).
- SVG-Bilder werden als React-Komponenten in das Projekt importiert und mithilfe von Webpack in HTML eingebettet.
- . .
- CSS.
- , , HTML-
<button>. - Safari ( 13 ).
Werfen wir einen Blick auf den Fehler und überlegen, ob wir Annahmen darüber treffen können, was los ist. Die Gründe für solche Fehler liegen normalerweise nicht irgendwo auf der Oberfläche, daher kann man angesichts solcher Fehler nicht sofort mit Sicherheit sagen, was passiert. Bei unserem ersten Versuch, ein Problem zu verstehen, müssen wir uns nicht bemühen, seine Ursache mit 100% iger Genauigkeit zu identifizieren. Wir werden den Fehler Schritt für Schritt untersuchen und Hypothesen formulieren und testen, die uns helfen, die Liste der möglichen Ursachen für das Geschehen einzugrenzen.
Eine Hypothese formulieren
Auf den ersten Blick sieht das, was passiert, wie ein CSS-Fehler aus. Wenn Sie mit der Maus über die Schaltfläche fahren, werden möglicherweise einige Stile darauf angewendet, die das Layout beschädigen. Vielleicht ist das
overflowSVG-Bildattribut schuld . Darüber hinaus besteht das Gefühl, dass ein Fehler ohne ein bestimmtes System auftritt, wenn die Seite aus verschiedenen Gründen neu gezeichnet wird (ein Ereignis, paintwenn die Größe des Browserfensters geändert wird, wenn sich der Mauszeiger über einer Schaltfläche befindet, wenn darauf geklickt wird usw.).
Beginnen wir mit der einfachsten und offensichtlichsten Annahme. Angenommen, der Fehler liegt im CSS. Wir können davon ausgehen, dass im Safari-Browser ein Fehler vorliegt, der zu einer falschen SVG-Ausgabe führt, wenn bestimmte Stile auf SVG-Elemente angewendet werden. Zum Beispiel wie die Stile, die zum Erstellen von Flex-Layouts verwendet werden.
Wir haben gerade eine Hypothese formuliert. Unser nächster Schritt besteht darin, einen Test durchzuführen, der diese Hypothese entweder bestätigt oder widerlegt. Das Ergebnis jedes Tests gibt uns neue Informationen über den Fehler und hilft bei der Formulierung der folgenden Hypothesen.
Das Problem vereinfachen
Wir werden eine Debugging-Strategie namens "Vereinfachung des Problems" verwenden. Auf diese Weise können wir den genauen Ort des Fehlers bestimmen. In einer Vorlesung über Informatik an der Cornell University wird diese Strategie als "Ansatz zur schrittweisen Beseitigung von Code, der nicht mit Fehlern zusammenhängt" beschrieben.
Unter der Annahme, dass der Fehler im CSS liegt, können wir schließlich entweder die Fehlerursache finden oder das CSS aus der Gleichung ausschließen, wodurch die Anzahl der möglichen Fehlerursachen und die Komplexität des Problems verringert werden.
Testen wir unsere Hypothese. Versuchen wir es zu bestätigen. In diesem Fall sollte der Fehler nicht mehr angezeigt werden, wenn Sie vorübergehend alle nicht standardmäßigen Stile auf der Seite deaktivieren.
Hier ist der Code, der das entsprechende Stylesheet enthält:
import 'css/app.css';
Ich habe dieses CodePen-Projekt erstellt , um die Ausgabe von Elementen ohne CSS zu demonstrieren . In React werden SVG-Grafiken als Komponente in ein Projekt importiert , und der entsprechende Code wird mithilfe von Webpack in HTML eingebettet.

Normale
Schaltflächenansicht Wenn Sie das oben genannte Projekt in Safari öffnen und auf eine der großen Schaltflächen klicken, wird der Fehler weiterhin angezeigt. Es passiert auch, wenn die Seite geladen wird, aber wenn Sie CodePen verwenden, müssen Sie auf die Schaltfläche klicken, um einen Fehler auszulösen.

Der Fehler blieb auch dann bestehen, wenn CSS deaktiviert wurde (Safari 13).
Daher können wir den Schluss ziehen, dass CSS nichts damit zu tun hat. Wir können jedoch darauf achten, dass unter solchen Bedingungen nur zwei der fünf Schaltflächen falsch angezeigt werden. Erinnern wir uns daran und fahren wir mit der nächsten Hypothese fort.
Fehlerisolation
Unsere nächste Hypothese ist, dass Safari einen Fehler beim Rendern von SVG-Bildern in HTML-Elementen hat
<button>. Da das Problem auftritt, wenn die ersten beiden Schaltflächen angezeigt werden, isolieren wir die erste und sehen, was passiert.
Sara Drazner dabeiDas Material erklärt die Bedeutung der Isolierung. Ich empfehle dieses Material jedem, der mehr über Debugging-Tools und verschiedene Ansätze zum Auffinden von Fehlern erfahren möchte. Hier ein Zitat aus diesem Material: „Isolation ist vielleicht das wichtigste Grundprinzip des Debuggens. Der Code, der in unseren Projekten funktioniert, kann auf verschiedene Bibliotheken und Frameworks verteilt sein. Viele Menschen sind möglicherweise an der Arbeit an Projekten beteiligt, und einige derjenigen, die zur Entwicklung der Projekte beigetragen haben, arbeiten nicht mehr an ihnen. Das Isolieren des Problems hilft uns, langsam abzuschneiden, was den Fehler nicht verursacht. Dies ermöglicht es letztendlich, die Ursache des Problems zu finden und sich darauf zu konzentrieren. "
Die Fehlerisolierung wird häufig als " Kurztest " bezeichnet.
Ich habe die Schaltfläche auf eine separate leere Seite verschoben (einen separaten Test dafür erstellt). Dieses CodePen-Projekt wurde nämlich erstellt , um eine Schaltfläche isoliert zu untersuchen. Obwohl wir zu dem Schluss gekommen sind, dass CSS nicht die Ursache des Problems ist, müssen wir Stile deaktiviert lassen, bis wir die wahre Ursache des Problems ermitteln. Dadurch können wir das Problem so weit wie möglich vereinfachen.

Eine Seite mit nur einer Schaltfläche
Wenn Sie dieses Projekt in Safari öffnen, stellt sich heraus, dass wir keinen Fehler mehr verursachen können. Auch nach dem Klicken auf die Schaltfläche ändert sich das Bild nicht. Dies kann jedoch nicht als akzeptable Lösung für das Problem angesehen werden. Der Code für dieses CodePen-Projekt bietet uns jedoch eine hervorragende Grundlage für die Erstellung eines minimal reproduzierbaren Beispiels.
Minimal reproduzierbares Beispiel
Der Hauptunterschied zwischen den beiden vorherigen CodePen-Projekten ist die Tastenkombination. Wenn wir alle möglichen Tastenkombinationen untersuchen, können wir den Schluss ziehen, dass das Problem nur auftritt, wenn ein Ereignis
paintfür ein größeres SVG-Bild auftritt, neben dem sich ein kleineres SVG-Bild auf der Seite befindet.
Wenn wir dies wussten, konnten wir ein minimales, reproduzierbares Beispiel erstellen, mit dem wir den Fehler reproduzieren und dennoch unnötige Elemente entfernen konnten. Dank eines minimal reproduzierbaren Beispiels können wir das Problem genauer untersuchen und genau den Teil des Codes hervorheben, der es verursacht.
Hier ist das fragliche CodePen-Projekt.

Minimal reproduzierbares Beispiel
Wenn Sie dieses Projekt in Safari öffnen und auf die Schaltfläche klicken, tritt erneut ein Problem auf. Auf diese Weise können wir eine Hypothese formulieren, dass die beiden SVG-Elemente irgendwie miteinander in Konflikt stehen. Wenn Sie das zweite SVG-Bild über das erste legen, stellt sich heraus, dass die Größe der Reste des Hintergrunds des ersten Bildes genau mit der Größe des kleineren Bildes übereinstimmt.

Eine Zeichnung, in der das zweite Bild über dem ersten platziert wird, verzerrt durch einen Fehler
Teile und herrsche
Wir konnten den Fehler mit der Mindestanzahl von Elementen reproduzieren, die durch ein Paar SVG-Bilder dargestellt werden. Jetzt werden wir den Umfang des Problems weiter eingrenzen und ihn auf den spezifischen Teil des SVG-Codes eingrenzen, der die Ursache des Problems ist. Wenn wir SVG-Code allgemein verstehen und dennoch die Ursache des Problems finden möchten, können wir eine binäre Baumsuchstrategie verwenden, die einen Divide-and-Conquer-Ansatz verwendet. Hier ist ein weiterer Auszug aus der Vorlesungvon der Cornell University Computer Science: „Sie können beispielsweise zunächst einen großen Teil des Codes untersuchen und den Validierungscode in der Mitte des zu untersuchenden Teils platzieren. Wenn hier kein Fehler auftritt, bedeutet dies, dass sich die Quelle in der zweiten Hälfte des Codes befindet. Andernfalls befindet sich die Quelle in der ersten Hälfte des Codes. "
Wenn Sie den SVG-Code untersuchen, können Sie versuchen, ein Element
<filter>aus der Beschreibung des ersten Bildes zu entfernen (und auch <defs>, da dieser Block sowieso nichts enthält). Interessieren wir uns für die Art der Aufgaben, die das Element löst <filter>. Eine gute Erklärung dafür finden Sie hier . Wir sprechen nämlich über Folgendes: „Um Filter auf SVG-Bilder anzuwenden, gibt es ein spezielles Element namens<filter>... Es ähnelt im Wesentlichen Elementen, die für die Arbeit mit linearen Verläufen, Masken, Vorlagen und anderen Grafikeffekten ausgelegt sind. Das Element wird <filter>niemals alleine angezeigt. Es wird nur als etwas verwendet, auf das mithilfe eines Attributs filterim SVG-Code oder einer Funktion url()in CSS verwiesen werden kann . "
In unserem SVG-Bild wird ein Filter verwendet, um einen kleinen inneren Schatten am unteren Rand des Bildes hinzuzufügen. Nachdem wir den Filter aus dem Code des ersten Bildes entfernt haben, warten wir, bis dieser Schatten verschwindet. Wenn das Problem danach weiterhin besteht, können wir den Schluss ziehen, dass mit dem anderen Code zur Beschreibung des SVG-Elements etwas nicht stimmt.
Ich habe ein weiteres CodePen-Projekt erstellt, um die Ergebnisse dieses Tests zu demonstrieren.

Folgen des Entfernens des <filter> -Elements
Das Problem ist, wie Sie leicht sehen können, nirgendwo aufgetreten. Und der innere Schatten wird auch nach dem Entfernen des Filtercodes weiterhin angezeigt. Jetzt tritt das Problem unter anderem in allen Browsern auf. Dies lässt den Schluss zu, dass der Fehler irgendwo im Rest des Schaltflächenbeschreibungscodes liegt. Wenn Sie den Restentfernen
idaus<g filter="url(#filter0_ii)">, dann verschwindet der Schatten. Was ist hier los?
Schauen wir uns die obige Definition eines Elements noch einmal an
<filter>und beachten Sie die folgenden Wörter: „Ein Element wird<filter>niemals alleine angezeigt. Es wird nur als etwas verwendet, auf das mithilfe eines Attributsfilterin SVG verwiesen werden kann . " (Ich habe ein Fragment des Textes hervorgehoben.)
Wenn wir dies wissen, können wir schließen, dass die Filterdeklaration aus dem zweiten SVG-Bild auf das erste SVG-Bild angewendet wird, was zu dem Fehler führt.
Bug-Fix
Wir wissen jetzt, dass unser Problem elementbezogen ist
<filter>. Wir wissen auch, dass beide SVG-Bilder dieses Element haben, da der Filter verwendet wird, um einen kreisförmigen inneren Schatten zu erzeugen. Vergleichen wir den Code von zwei SVG-Bildern und sehen wir, ob wir den Fehler erklären und beheben können.
Ich habe den Code beider Bilder vereinfacht, damit Sie klar sehen können, was darin passiert.
Hier ist der Code für das erste SVG-Bild:
<svg width="46" height="46" viewBox="0 0 46 46">
<g filter="url(#filter0_ii)">
<!-- ... -->
</g>
<!-- ... -->
<defs>
<filter id="filter0_ii" x="0" y="0" width="46" height="46">
<!-- ... -->
</filter>
</defs>
</svg>
Hier ist der Code für das zweite Bild:
<svg width="28" height="28" viewBox="0 0 28 28">
<g filter="url(#filter0_ii)">
<!-- ... -->
</g>
<!-- ... -->
<defs>
<filter id="filter0_ii" x="0" y="0" width="28" height="28">
<!-- ... -->
</filter>
</defs>
</svg>
Wenn Sie diese beiden Fragmente analysieren, können Sie feststellen, dass in der Konstruktion
id=filter0_iidieselbe Kennung verwendet wird. Safari wendet die zuletzt vom Browser analysierte Filterdefinition auf die Elemente an (in diesem Fall den Filter des zweiten Bildes). Dies führt dazu, dass das erste Bild zugeschnitten wird. Die ursprüngliche Größe ist 48px, und nach dem Aufbringen des Filters wird ein Stück herausgeschnitten 26px. Die idDOM- Eigenschaft muss einen eindeutigen Wert haben. Wenn die Seite mehrere identische enthält, idkann der Browser nicht herausfinden, welche er verwenden muss. Und da die Eigenschaft filterbeim Auftreten jedes Ereignisses überschrieben wirdpaintJe nachdem, welche der Definitionen zuerst bereit ist (hier tritt so etwas wie eine Race-Bedingung auf), wird der Fehler entweder angezeigt oder nicht.
Lassen Sie uns versuchen, eindeutige Werte
idim Code jedes der Bilder zuzuweisen und die Ergebnisse anzuzeigen. Hier ist das entsprechende CodePen-Projekt.

Das Zuweisen eindeutiger IDs hat das Problem behoben.
Wenn Sie jetzt das Projekt in Safari öffnen und auf die Schaltfläche klicken, können Sie sicher sein, dass wir das Problem gelöst haben, indem Sie eindeutige
idFilterzuweisen, die in SVG-Bildern verwendet werden. Wenn Sie an die Tatsache denken, dass das Projekt nicht eindeutige Werte für ein Attribut wie hatteid, führt dies zu der Schlussfolgerung, dass das Problem in allen Browsern und nicht nur in Safari auftreten sollte. Aus irgendeinem Grund scheinen andere Browser (einschließlich Chrome und Firefox) diese ungewöhnliche Situation fehlerfrei bewältigt zu haben. Es könnte jedoch ein Zufall sein.
Ergebnis
Es war ein weiteres Abenteuer! Wir begannen nur zu wissen, dass es einen Fehler im Projekt gab, der manchmal auftritt und dann nicht auftritt, aber am Ende haben wir die Gründe für das Geschehen vollständig verstanden und das Problem bewältigt. Das Debuggen von Benutzeroberflächencode und das Herausfinden, warum Grafiken verzerrt sind, kann schwierig sein, wenn Sie nicht verstehen, was passiert. Zum Glück gibt es Debugging-Strategien, mit denen wir die Ursache selbst der verwirrendsten Fehler finden können.
Zunächst haben wir das Problem vereinfacht, indem wir Hypothesen formuliert haben, mit denen wir Komponenten aus dem Projekt entfernen konnten, die nicht mit dem Fehler zusammenhängen (Stile, Markups, dynamische Ereignisse usw.). Danach haben wir das Markup isoliert und ein minimal reproduzierbares Beispiel gefunden. Dadurch konnten wir uns auf ein kleines Stück Code konzentrieren. Und schließlich haben wir das Problem mithilfe einer Divide and Conquer-Strategie identifiziert, um den Fehler zu beseitigen.
Vielen Dank an alle, die sich die Zeit genommen haben, diesen Artikel zu lesen. Bevor wir das Gespräch beenden, möchte ich Ihnen noch eine andere Debugging-Strategie erläutern, die in den Vorlesungen erwähnt wird.Cornell Universität. Der Punkt ist, dass Sie während der Arbeit Pausen einlegen, sich ausruhen und Ihren Kopf von allen Gedanken befreien müssen: „Wenn das Debuggen zu lange dauert, wird der Programmierer müde. Es kann sich herausstellen, dass er in einem solchen Zustand vergeblich arbeitet. In einer solchen Situation lohnt es sich, eine Pause einzulegen und alles aus dem Kopf zu werfen. Und nach einer Weile lohnt es sich, das Problem aus einem anderen Blickwinkel zu betrachten. "
Wie behebt man unverständliche Fehler?
