搜索
首页web前端css教程这是我如何使用经过久经考验的调试策略来解决一个怪异的错误

Here’s How I Solved a Weird Bug Using Tried and True Debugging Strategies

还记得上次你遇到一个让你抓耳挠腮几个小时的UI相关bug吗?也许问题是随机发生的,或者在特定情况下出现(设备、操作系统、浏览器、用户操作),或者只是隐藏在项目中众多前端技术之一中?

我最近再次体会到UI bug的复杂性。我最近修复了一个有趣的bug,它影响了Safari浏览器中的一些SVG,没有任何明显的模式或原因。我搜索过任何类似的问题,希望能找到一些线索,但没有找到有用的结果。尽管有障碍,我还是设法解决了它。

我通过使用一些有用的调试策略来分析问题,这些策略我也将在本文中介绍。提交修复程序后,我想起了Chris之前发布的一条推文。

写下你希望在谷歌搜索时找到的那篇文章。

— Chris Coyier (@chriscoyier) 2017年10月30日

……我们来了。

问题描述

我在一个正在进行的项目中发现了以下bug。这是在一个上线的网站上。

我创建了一个CodePen示例来演示这个问题,以便您可以自己检查它。如果我们在Safari中打开示例,按钮在加载时可能看起来符合预期。但是,如果我们点击前两个较大的按钮,问题就会出现。

每当浏览器绘制事件发生时较大按钮中的SVG渲染不正确。它只是被截断了。它可能在加载时随机发生。它甚至可能在调整屏幕大小时发生。无论情况如何,它都会发生!

以下是我解决这个问题的方法。

首先,让我们考虑一下环境

回顾项目的细节以了解环境和存在bug的条件总是一个好主意。

  • 这个特定的项目使用React(但这篇文章不需要)。
  • SVG作为React组件导入,并通过webpack内联到HTML中。
  • SVG是从设计工具导出的,没有语法错误。
  • SVG应用了一些来自样式表的CSS。
  • 受影响的SVG位于一个HTML <div> 元素内。 <li>问题只出现在Safari中(在13版本上被注意到)。</li> <h3 id="深入问题">深入问题</h3> <p>让我们来看看这个问题,看看我们能否对正在发生的事情做出一些假设。像这样的bug会变得很复杂,我们不会立即知道发生了什么。我们不必在第一次尝试时就100%正确,因为我们将逐步进行,形成我们可以测试的假设,以缩小可能的原因。</p> <h3 id="形成假设">形成假设</h3> <p>起初,这看起来像是一个CSS问题。某些样式可能会在悬停事件中应用,从而破坏SVG图形的布局或溢出属性。它也看起来像是问题随机发生,每当Safari渲染页面时(调整屏幕大小、悬停、点击等时的绘制事件)。</p> <p>让我们从简单而最明显的途径开始,并假设CSS是问题的根源。我们可以考虑Safari浏览器中存在一个bug的可能性,该bug会导致在某些特定样式应用于SVG元素(例如flex布局)时SVG渲染不正确。</p> <p>通过这样做,我们<strong>形成了一个假设</strong>。我们的下一步是设置一个测试,该测试要么证实要么反驳该假设。每个测试结果都会产生关于bug的新事实,并有助于形成进一步的假设。</p> <h3 id="问题简化">问题简化</h3> <p>我们将使用一种称为<strong>问题简化</strong>的调试策略来尝试查明问题。康奈尔大学的CS讲座将此策略描述为“一种逐渐消除与bug无关的代码部分的方法”。</p> <p>通过假设问题在于CSS,我们可以最终查明问题或从等式中消除CSS,从而减少可能原因的数量和问题的复杂性。</p> <p>让我们尝试确认我们的假设。如果我们暂时排除所有非浏览器样式表,则问题不应发生。我在我的源代码中通过注释掉项目中的以下代码行来做到这一点。</p> <pre class="brush:php;toolbar:false">&lt;code&gt;import 'css/app.css';&lt;/code&gt;</pre> <p>我创建了一个方便的CodePen示例来演示这些不包含CSS的元素。在React中,我们正在将SVG图形作为组件导入,并且它们使用webpack内联到HTML中。</p> <p>如果我们在Safari中打开这个pen并点击按钮,我们仍然会遇到这个问题。它仍然在页面加载时发生,但在CodePen上,我们必须通过点击按钮来强制它。我们可以得出结论,CSS不是罪魁祸首,但我们也可以看到只有五个按钮中的两个在这种情况下面临问题。让我们记住这一点,然后继续下一个假设。</p> <h3 id="隔离问题">隔离问题</h3> <p>我们的下一个假设指出,Safari在HTML <code><div> 元素内渲染SVG时存在bug。由于问题发生在前两个按钮上,我们将<strong>隔离第一个按钮</strong>,看看会发生什么。 <p>Sarah Drasner解释了隔离的重要性,如果您想了解有关调试工具和其他方法的更多信息,我强烈建议您阅读她的文章。</p> <blockquote> <p>隔离可能是所有调试中最强的核心原则。我们的代码库可能庞大,包含不同的库、框架,并且可能包含许多贡献者,甚至包括不再参与该项目的人员。隔离问题有助于我们慢慢剔除问题中不必要的部件,以便我们可以单独关注解决方案。</p> </blockquote> <p>它也经常被称为“简化的测试用例”。</p> <p>我将此按钮移动到一个单独的空测试路由(空白页面)。我创建了以下CodePen来演示该状态。即使我们已经得出结论,CSS不是问题的原因,我们也应该在找出bug的真正原因之前将其排除在外,以尽可能简化问题。</p> <p>如果我们在Safari中打开这个pen,我们可以看到我们<strong>无法再重现这个问题</strong>,并且<strong>SVG图形在点击按钮后按预期显示</strong>。<strong>我们不应该将此更改视为可接受的bug修复</strong>,但它为创建最小的可重现示例提供了一个良好的起点。</p> <h3 id="最小的可重现示例">最小的可重现示例</h3> <p>前两个示例之间的主要区别在于按钮组合。在尝试了所有可能的组合之后,我们可以得出结论,此问题仅在对同一页面上较小的SVG图形旁边的较大SVG图形发生绘制事件时才会发生。</p> <p>我们创建了一个<strong>最小的可重现示例</strong>,允许我们在没有任何不必要元素的情况下重现bug。使用最小的可重现示例,我们可以更详细地研究问题并准确地查明导致问题的代码部分。</p> <p>我创建了以下CodePen来演示最小的可重现示例。</p> <p>如果我们在Safari中打开此演示并点击按钮,我们可以看到问题正在发生,并形成一个假设,即这两个SVG以某种方式相互冲突。如果我们将第二个SVG图形叠加在第一个图形上,我们可以看到第一个SVG图形上被裁剪的圆圈的大小与较小的SVG图形的精确尺寸相匹配。</p> <h3 id="分而治之">分而治之</h3> <p>我们将问题缩小到两个SVG图形的组合。现在我们将把问题缩小到导致问题的特定SVG代码。如果我们只对SVG代码有基本的了解,并且想要查明问题,我们可以使用<strong>二叉树搜索</strong>策略,并采用分而治之的方法。康奈尔大学的CS讲座描述了这种方法:</p> <blockquote> <p>例如,从一大段代码开始,在代码中间放置一个检查点。如果错误没有出现在该点,则表示错误发生在后半部分;否则,它就在前半部分。</p> </blockquote> <p>在SVG中,我们可以尝试从第一个SVG中删除<code><filter></filter>(以及<defs></defs>,因为它无论如何都是空的)。让我们首先检查<filter></filter>的作用。Sara Soueidan的这篇文章最好地解释了它。

    与SVG中的线性渐变、蒙版、图案和其他图形效果一样,滤镜有一个方便命名的专用元素:<filter></filter> 元素。

    <filter></filter> 元素永远不会直接渲染;它唯一的用途是可以使用SVG中的filter属性或CSS中的url()函数来引用它。

    在我们的SVG中,<filter></filter>在SVG图形底部应用了一个轻微的内阴影。在我们将其从第一个SVG图形中删除后,我们预计内阴影将消失。如果问题仍然存在,我们可以得出结论,SVG标记的其余部分存在问题。如果我们从<g filter="url(#filter0_ii)"></g>中删除剩余的id,则阴影将完全移除。到底是怎么回事?

    让我们再看看前面提到的<filter></filter>属性的定义,并注意以下细节:

    <filter></filter> 元素永远不会直接渲染;它唯一的用途是可以被引用,使用SVG中的filter属性。

    (我的强调)

    因此,我们可以得出结论,第二个SVG图形的滤镜定义被应用于第一个SVG图形,并导致错误。

    修复问题

    我们现在知道问题与<filter></filter>属性有关。我们也知道这两个SVG都有filter属性,因为它们使用它来创建圆形上的内阴影。让我们比较这两个SVG之间的代码,看看我们能否解释和修复这个问题。

    我已经简化了两个SVG图形的代码,以便我们可以清楚地看到发生了什么。以下代码段显示了第一个SVG的代码。

    <code><svg height="46" viewbox="0 0 46 46" width="46"><g filter="url(#filter0_ii)"></g><defs><filter height="46" width="46" x="0" y="0"></filter></defs></svg></code>

    以下代码段显示了第二个SVG图形的代码。

    <code><svg height="28" viewbox="0 0 28 28" width="28"><g filter="url(#filter0_ii)"></g><defs><filter height="28" width="28" x="0" y="0"></filter></defs></svg></code>

    我们可以注意到,生成的SVG使用相同的id属性id=filter0_ii。Safari应用了它最后读取的滤镜定义(在本例中是第二个SVG标记),并导致第一个SVG被裁剪到第二个滤镜的大小(从46px到28px)。id属性在DOM中应该具有唯一值。通过在一个页面上拥有两个或多个id属性,浏览器无法理解要应用哪个引用,并且滤镜属性在每次绘制事件中重新定义,这取决于导致问题随机出现的竞争条件。

    让我们尝试为每个SVG图形分配唯一的id属性值,看看是否能解决这个问题。

    如果我们在Safari中打开CodePen示例并点击按钮,我们可以看到通过为每个SVG图形文件中<filter></filter>属性分配唯一的ID,我们修复了这个问题。如果我们考虑这样一个事实:我们为像id这样的属性具有非唯一值,这意味着此问题应该存在于所有浏览器上。出于某种原因,其他浏览器(包括Chrome和Firefox)似乎在没有任何bug的情况下处理了这个边缘情况,尽管这可能只是一个巧合。

    总结

    这是一次相当长的旅程!我们从几乎对一个看似随机发生的问题一无所知,到完全理解并修复它。如果问题的根本原因不明确或复杂,调试UI和理解视觉bug可能很困难。幸运的是,一些有用的调试策略可以帮助我们。

    首先,我们通过形成假设来简化问题,这帮助我们消除了与问题无关的组件(样式、标记、动态事件等)。之后,我们隔离了标记,并找到了最小的可重现示例,这使我们能够专注于单个代码块。最后,我们使用分而治之的策略查明了问题,并修复了它。

    感谢您抽出时间阅读这篇文章。在我离开之前,我想给您留下最后一种调试策略,它也在康奈尔大学的CS讲座中有所介绍。

    记住在调试尝试之间休息一下,放松并清理你的思绪

    如果在bug上花费了太多时间,程序员就会感到疲倦,调试可能会适得其反。休息一下,清理你的思绪;休息之后,尝试从不同的角度思考这个问题。

    参考

    • 康奈尔大学CS 312讲座26 – 调试技术
    • 调试技巧和窍门
    • 简化的测试用例
    • SVG滤镜101

以上是这是我如何使用经过久经考验的调试策略来解决一个怪异的错误的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
CSS旋转木马内的卷轴驱动动画CSS旋转木马内的卷轴驱动动画May 16, 2025 am 09:50 AM

嘿,不是与滚动区域一起使用的相当新的CSS功能吗?哦,是的,那是卷轴驱动的动画。是否应该在滚动浏览CSS旋转木马中的项目时触发动画吗?

CSS包含:为您的项目选择正确的方法CSS包含:为您的项目选择正确的方法May 16, 2025 am 12:02 AM

ThebestmethodforincludingCSSdependsonprojectsizeandcomplexity:1)Forlargerprojects,useexternalCSSforbettermaintainabilityandperformance.2)Forsmallerprojects,internalCSSissuitabletoavoidextraHTTPrequests.Alwaysconsidermaintainabilityandperformancewhenc

这不应该发生:对不可能进行故障排除这不应该发生:对不可能进行故障排除May 15, 2025 am 10:32 AM

解决这些不可能的问题之一,这是您从未想过的其他问题的问题。

@KeyFrames vs CSS过渡:有什么区别?@KeyFrames vs CSS过渡:有什么区别?May 14, 2025 am 12:01 AM

@keyframesandCSSTransitionsdifferincomplexity:@keyframesallowsfordetailedanimationsequences,whileCSSTransitionshandlesimplestatechanges.UseCSSTransitionsforhovereffectslikebuttoncolorchanges,and@keyframesforintricateanimationslikerotatingspinners.

使用页面CMS进行静态站点内容管理使用页面CMS进行静态站点内容管理May 13, 2025 am 09:24 AM

我知道,我知道:有大量的内容管理系统选项可用,而我进行了几个测试,但实际上没有一个是一个,y&#039;知道吗?怪异的定价模型,艰难的自定义,有些甚至最终成为整个&

链接HTML中CSS文件的最终指南链接HTML中CSS文件的最终指南May 13, 2025 am 12:02 AM

链接CSS文件到HTML可以通过在HTML的部分使用元素实现。1)使用标签链接本地CSS文件。2)多个CSS文件可通过添加多个标签实现。3)外部CSS文件使用绝对URL链接,如。4)确保正确使用文件路径和CSS文件加载顺序,优化性能可使用CSS预处理器合并文件。

CSS Flexbox与网格:全面评论CSS Flexbox与网格:全面评论May 12, 2025 am 12:01 AM

选择Flexbox还是Grid取决于布局需求:1)Flexbox适用于一维布局,如导航栏;2)Grid适合二维布局,如杂志式布局。两者在项目中可结合使用,提升布局效果。

如何包括CSS文件:方法和最佳实践如何包括CSS文件:方法和最佳实践May 11, 2025 am 12:02 AM

包含CSS文件的最佳方法是使用标签在HTML的部分引入外部CSS文件。1.使用标签引入外部CSS文件,如。2.对于小型调整,可以使用内联CSS,但应谨慎使用。3.大型项目可使用CSS预处理器如Sass或Less,通过@import导入其他CSS文件。4.为了性能,应合并CSS文件并使用CDN,同时使用工具如CSSNano进行压缩。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具