最近有人问我如何处理内联 SVG 的调试。因为它属于 DOM 的一部分,所以我们可以在任何浏览器的 DevTools 中检查任何内联 SVG。因此,我们能够对事物进行范围界定,并发现任何潜在问题或优化 SVG 的机会。
但有时,我们根本无法看到我们的 SVG。在这些情况下,在进行调试时,我会寻找六个特定方面。
viewBox
值
1. 在使用 SVG 时,viewBox
是一个常见的混淆点。从技术上讲,在没有它的情况下使用内联 SVG 也没问题,但我们会失去它最重要的优势之一:随容器缩放。同时,如果配置不当,它可能会对我们不利,导致出现不需要的裁剪。
当元素被裁剪时,它们仍然存在——只是在我们看不到的坐标系的一部分中。如果我们在某些图形编辑程序中打开该文件,它可能看起来像这样

最简单的解决方法是什么?在 SVG 中添加 overflow="visible"
,无论是在我们的样式表中、内联在 style
属性中还是直接作为 SVG 表示属性。但是,如果我们还将 background-color
应用于 SVG 或周围有其他元素,则外观可能会略有偏差。在这种情况下,最佳选择是编辑 viewBox
以显示隐藏的坐标系部分。
overflow="hidden"
和编辑 viewBox。在讨论 viewBox
的同时,还有一些其他值得关注的事项。
viewBox
是如何工作的?
SVG 是一个无限画布,但我们可以通过视口和 viewBox
控制我们看到的内容以及如何看到它。
视口是在无限画布上的一个窗口框架。它的尺寸由 width
和 height
属性定义,或者在 CSS 中使用相应的 width
和 height
属性定义。我们可以指定任何我们想要的长度单位,但如果我们提供无单位的数字,则默认为像素。
viewBox
由四个值定义。前两个是左上角的起始点(x
和 y
值,允许使用负数)。我正在编辑这些值以重新构图。后两个是视口中坐标系的宽度和高度——在这里我们可以编辑网格的比例(我们将在关于缩放的部分中详细介绍)。
以下简化的标记显示了 SVG viewBox
和在 <svg>
上同时设置的 width
和 height
属性
<svg viewBox="0 0 700 700" width="700" height="700">
<!-- etc. -->
</svg>
重新构图
所以,这
<svg viewBox="0 0 700 700">
…映射到这
<svg viewBox="start-x-axis start-y-axis width height">
我们看到的视口从 x 轴上的 0
和 y 轴上的 0
相交处开始。
通过更改这
<svg viewBox="0 0 700 700">
…到这
<svg viewBox="300 200 700 700">
…宽度和高度保持不变(每个 700
个单位),但坐标系的起点现在位于 x 轴上的 300
点和 y 轴上的 200
点。
在下面的视频中,我向 SVG 添加了一个红色的 <circle>
,其中心位于 x 轴上的 300
点和 y 轴上的 200
点。请注意,将 viewBox
坐标更改为相同的值也会将圆圈的位置更改到框架的左上角,而 SVG 的渲染大小保持不变(700
×700
)。我所做的只是使用 viewBox
“重新构图”。
缩放
我们可以更改 viewBox
内的后两个值以放大或缩小图像。值越大,要适应视口的 SVG 单位就越多,从而导致图像变小。如果我们想要保持 1:1 的比例,则我们的 viewBox
宽度和高度必须与我们的视口宽度和高度值匹配。
让我们看看在 Illustrator 中更改这些参数时会发生什么。画板是 viewport
,由一个白色的 700px 正方形表示。该区域之外的所有内容都是我们的无限 SVG 画布,默认情况下会被裁剪。
下面的图 1 显示了一个蓝色点,它位于 x 轴上的 900
和 y 轴上的 900
。如果我将后两个 viewBox
值从 700
更改为 900
,如下所示
<svg viewBox="300 200 900 900" width="700" height="700">
…那么蓝色点几乎完全回到了视野中,如下面的图 2 所示。我们的图像已缩小,因为我们增加了 viewBox 值,但 SVG 的实际宽度和高度尺寸保持不变,并且蓝色点回到了更靠近未裁剪区域的位置。


有一个粉红色的正方形作为网格如何缩放以适应视口的证据:单位变小,并且更多网格线适合相同的视口区域。您可以在以下 Pen 中使用相同的值来查看其工作原理。
width
和 height
2. 缺少 在调试内联 SVG 时,我还会查看的另一个常见问题是标记中是否包含 width
或 height
属性。在许多情况下,这没什么大不了的,除非 SVG 位于具有绝对定位或弹性容器的容器内(因为 Safari 使用 0px
而不是 auto
计算 SVG width
值)。在这些情况下,排除 width
或 height
会阻止我们看到完整的图像,正如我们可以通过打开此 CodePen 演示并在 Chrome、Safari 和 Firefox 中进行比较(点击图像以查看更大的视图)看到的那样。
解决方案?添加宽度或高度,无论是作为表示属性、内联在 style
属性中还是在 CSS 中。避免单独使用高度,尤其是在将其设置为 100%
或 auto
时。另一种解决方法是设置 right
和 left
值。
您可以使用以下 Pen并结合不同的选项。
fill
和 stroke
颜色
3. 无意中的 也可能是我们正在将颜色应用于 <svg>
标签,无论是内联样式还是来自 CSS。这很好,但标记或样式中可能还有其他与 <svg>
上设置的颜色冲突的颜色值,导致部分内容不可见。
因此,我倾向于在 SVG 的标记中查找 fill
和 stroke
属性并将其删除。以下视频显示了一个我在 CSS 中使用红色 fill
进行样式化的 SVG。在几个地方,SVG 的部分直接在标记中以白色填充,我将其删除以显示缺失的部分。
4. 缺少 ID
这可能看起来非常明显,但你会惊讶地发现我经常看到它出现。假设我们在 Illustrator 中制作了一个 SVG 文件,并且非常仔细地命名了图层,以便在导出文件时获得很好的匹配 ID。并且假设我们计划通过挂钩到这些 ID 在 CSS 中为该 SVG 设置样式。
这是一种很好的处理方式。但是,我见过很多次将同一个 SVG 文件第二次导出到同一个位置,而 ID 却不同,通常是在直接复制/粘贴矢量时发生这种情况。也许添加了一个新图层,或者其中一个现有图层被重命名了,或者其他什么原因。无论如何,CSS 规则不再与 SVG 标记中的 ID 匹配,导致 SVG 的渲染效果与预期不同。

在大型 SVG 文件中,我们可能很难找到这些 ID。此时,打开 DevTools,检查图形中不正常的部分,看看这些 ID 是否仍然匹配是一个好方法。
因此,我建议在交换任何内容之前,在代码编辑器中打开导出的 SVG 文件,并将其与原始文件进行比较。像 Illustrator、Figma 和 Sketch 这样的应用程序很智能,但这并不意味着我们不需要对它们进行审查。
5. 修剪和蒙版的检查清单
如果 SVG 被意外修剪,并且 viewBox
检查结果正常,我通常会查看 CSS 中是否存在可能干扰图像的 clip-path
或 mask
属性。查看内联标记很容易让人分心,但要记住,SVG 的样式可能在其他地方设置。
CSS 修剪和蒙版 允许我们“隐藏”图像或元素的部分内容。在 SVG 中,<clipPath>
是一种矢量操作,可以剪切图像的部分内容,没有中间结果。<mask>
标签是一种像素操作,允许透明度、半透明效果和模糊边缘。
这是一个用于调试涉及修剪和蒙版情况的小型检查清单
- 确保修剪路径(或蒙版)和图形相互重叠。重叠的部分是显示的部分。
- 如果有一个复杂的路径没有与您的图形相交,请尝试应用转换,直到它们匹配。
- 即使
<clipPath>
或<mask>
没有渲染,您仍然可以使用 DevTools 检查内部代码,所以请使用它! - 复制
<clipPath>
和<mask>
内部的标记,并将其粘贴到</svg>
标签之前。然后为这些形状添加一个fill
,并检查 SVG 的坐标和尺寸。如果仍然看不到图像,请尝试向<svg>
标签添加overflow="hidden"
。 - 检查是否为
<clipPath>
或<mask>
使用了**唯一的** ID,以及是否将相同的 ID 应用于被修剪或蒙版的形状或形状组。不匹配的 ID 将破坏外观。 - 检查
<clipPath>
或<mask>
标签之间的标记中是否存在错别字。 fill
、stroke
、opacity
或应用于<clipPath>
内元素的其他样式都是无用的——唯一有用的部分是这些元素的填充区域几何形状。这就是为什么如果使用<polyline>
,它将表现为<polygon>
,而如果使用<line>
,则不会看到任何修剪效果。- 如果在应用
<mask>
后看不到图像,请确保蒙版内容的fill
不是纯黑色。蒙版元素的亮度决定了最终图形的不透明度。您将能够透过较亮的部分看到,而较暗的部分将隐藏图像的内容。
您可以在这个 Pen中体验蒙版和修剪元素。
6. 命名空间
您知道 SVG 是一种基于 XML 的标记语言吗?是的,它是!SVG 的命名空间设置在 xmlns
属性上。
<svg xmlns="http://www.w3.org/2000/svg">
<!-- etc. -->
</svg>
关于 XML 中的命名空间有很多需要了解的,MDN 对此有一个很好的入门介绍。简单来说,命名空间为浏览器提供上下文,告知它该标记特定于 SVG。其思想是,当同一个文件中存在多种类型的 XML(如 SVG 和 XHTML)时,命名空间有助于防止冲突。这在现代浏览器中是一个不太常见的问题,但可能有助于解释旧版浏览器或像 Gecko 这样在定义文档类型和命名空间时非常严格的浏览器中出现的 SVG 渲染问题。
SVG 2 规范不要求在使用 HTML 语法时使用命名空间。但是至关重要如果支持旧版浏览器是优先事项——此外,添加它也没有任何坏处。这样,当 <html>
元素的 xmlns
属性被定义时,它在那些罕见的情况下就不会发生冲突。
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="700px" height="700px">
<!-- etc. -->
</svg>
</body>
</html>
这在 CSS 中使用内联 SVG 时也适用,例如将其设置为背景图像。在下面的示例中,在成功验证后,输入框后面会出现一个复选标记图标。CSS 看起来是这样的
textarea:valid {
background: white url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26">\
<circle cx="13" cy="13" r="13" fill="%23abedd8"/>\
<path fill="none" stroke="white" stroke-width="2" d="M5 15.2l5 5 10-12"/>\
</svg>') no-repeat 98% 5px;
}
当我们删除 background 属性中 SVG 内部的命名空间时,图像就会消失。
另一个常见的命名空间前缀是 xlink:href
。当引用 SVG 的其他部分(如:图案、滤镜、动画或渐变)时,我们经常使用它。建议开始将其替换为 href
,因为另一个自 SVG 2 以来已被弃用,但可能会与旧版浏览器存在兼容性问题。在这种情况下,我们可以同时使用两者。如果您仍在使用 xlink:href
,请记住包含命名空间 xmlns:xlink="http://www.w3.org/1999/xlink"
。
提升你的 SVG 技能!
我希望这些技巧能帮助您节省大量时间,如果您发现自己正在排查渲染不正确的内联 SVG。这些只是我寻找的东西。也许您有不同的危险信号需要关注——如果有,请在评论中告诉我!
最重要的是,至少要对SVG 的各种使用方法有一个基本的了解。 CodePen Challenges 经常包含 SVG 并提供良好的练习。以下是一些提升技能的资源
- 使用 SVG 与 CSS3 和 HTML5(Amelia Bellamy-Royds、Kurt Cagle、Dudley Storey)——我认为它是 SVG 圣经。
- Lea Verou 拥有丰富的 SVG 知识,并且多次在主题演讲中谈到它(例如2019 年前端联合大会上的这段视频)。
- SVG 动画(Sarah Drasner)
- SVG 基础(Amelia Bellamy-Royds、J. David Eisenberg)
- 实用 SVG(Chris Coyier)
有几个人我建议关注,以获取与 SVG 相关的优质内容
这些都是很棒的建议,我想在网页上使用 SVG 的上下文中再补充一点。问题可能根本不在于 SVG 本身,而是由于 CSS 定位、z-index 等。
基本上,所有可能导致
<img>
或<div>
出现问题的事情也可能应用于您的 SVG。我花了一些时间来调试由于页面本身的标记/样式而被隐藏/修剪的 SVG。这不是最佳的时间利用方式,因此始终值得再次检查visibility
、display
等,并确保 DevTools 显示<svg>
确实按预期显示在预期位置和方式。那是对的!这是一个很好的观点。
我唯一包含的是关于 flexbox 和 position absolute 行为的提及,但这是一个可以在单独的文章中扩展的想法。
我相信一个带有检查清单或文章的好的免责声明,可以首先检查可见性、显示、不透明度、大小等,会很有帮助 :)
感谢您的反馈!
看到其他人像我一样对 SVG 感兴趣总是很棒的。我们并不多!如果您不介意我在命名空间章节中添加一些内容,我将不胜感激。
有一个简单的规则:SVG 是 XML,需要在根元素上设置命名空间才能进行渲染(每个浏览器都对此保持一致)。即使它在 CSS 中内联为 data:uri。但当它在 HTML 中内联时,不需要命名空间(特别是对于
<html>
元素),就像您不需要type=text/javascript
用于您的<script>
一样。每个兼容 HTML5 的浏览器解析器都同意这种行为。并且每个浏览器至少十年来一直兼容 HTML5,但可能更久。我认为今天为旧版浏览器添加命名空间没有多大意义。我认为在典型现代网站的所有部分中,没有命名空间的 SVG 最终会失败 :)
嗨,Vadim!很高兴认识另一位 SVG 粉丝!:D
我完全同意你的观点,如果我在文章中没有表达清楚,请原谅,但老实说,我通常不会在 HTML 中使用 SVG 命名空间,并且从未遇到过此类问题。但不久前我在 CSS(如示例所示)或
xlink:href
中确实遇到过问题。我的目的是让任何人都意识到这一点,以防他们遇到类似的情况。
感谢您提出这一点!