响应式SVG

SVG(可缩放矢量图形)是一种用于描述二维矢量图形的XML标记语言。响应式SVG是指能够在不同屏幕尺寸和分辨率下适应并保持清晰度的SVG图形。

在响应式设计中,SVG图形可以通过各种技术和属性来实现适应性,以确保在不同设备上都能提供最佳显示效果。

SVG可能是一个棘手的主题。如果你是一名开发者,你可能需要对设计感兴趣,以深入了解SVG。而如果你是一名设计师,除了从设计工具(如Figma)导出文件,你还需要了解一些编码知识。这可能是为什么我们很少看到自定义响应式SVG,尽管它们非常有用且多才多艺。在这篇文章中,我将向你介绍创建响应式SVG的基础知识。

有一个有趣的设计元素,即一个小漩涡线将回复的头像与原始消息的头像连接起来。

这种设计是通过使用三个单独的SVG来实现的,其中最长部分的长度是通过JavaScript计算的,该JavaScript在页面加载时触发,以及每次窗口调整大小时触发。虽然这是一种有效的方法,但它严重依赖于JavaScript。相比之下,我想向你展示如何使用响应式SVG而完全不需要JS来实现类似的效果。

为了构建所需的图像,有三个基本的事物我们需要理解:viewBox 属性,preserveAspectRatio 属性以及SVG符号。

ViewBox基础知识

1
2
3
<svg viewBox="0 0 300 400" xmlns="http://www.w3.org/2000/svg">
...
</svg>

SVG中,将viewBox 想象成设计工具中的画板。例如,当你看到 viewBox="0 0 300 400" 时,类似于说:“创建一个宽300个单位、高400个单位的画板”。

请记住,我们正在使用矢量图形,所以最好不要以像素为单位思考,因为这些图形可以按任意尺寸缩放。

SVG还具有像任何其他图像一样的width和height属性。但是,有一个关键的区别:默认情况下,SVG的行为就像应用了 object-fit: contain 一样。这意味着,如果由widthheight设置的纵横比与viewBox定义的纵横比不同,你的“画板”将始终保持完全可见,并保持其比例而不发生扭曲。

为了增加一些复杂性,实际上你可以选择不定义viewBox。当发生这种情况时,SVG本身的实际宽度和高度成为我们的“画板”的尺寸。现在这可能听起来有点令人困惑,但别担心,我们稍后会更详细地探讨这个问题。

PreserveAspectRatio ↔ Object-fit

1
2
3
<svg viewBox="0 0 300 400" preserveAspectRatio="xMaxYMin" xmlns="http://www.w3.org/2000/svg">
...
</svg>

正如我之前提到的,SVG在行为上自然地就像它们有object-fit: contain一样。还有一个属性的作用类似于object-position,那就是preserveAspectRatio属性。

默认情况下,它被设置为preserveAspectRatio="xMidYMid",这会将画板居中。但是你可以更改此设置以模仿其他object-fit行为。例如,要复制object-fit: right top,你将使用preserveAspectRatio="xMaxYMin"。请记住,由于“contain”行为,只有其中一个定位规则会被应用。

SVG符号

当我们将SVG中的viewBox看作是画板时,SVG符号与设计工具(如Figma)中的组件非常相似。基本上,符号就像是一个小画板,它本身可以在另一个SVG中被插入(多次)。每个符号都有自己的viewBoxpreserveAspectRatio属性,定义了这个小画板的空间和边界。

要使用SVG符号,首先使用<symbol>元素定义它,并为其提供一个唯一的id。该符号充当模板。然后,您可以在SVG的任何位置使用<use>元素放置此模板,该元素引用符号的id

1
2
3
4
5
6
7
8
9
<svg viewBox="0 0 300 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="symbol" width="20" height="30" viewBox="0 0 20 30" >
...
</symbol>
</defs>
<!-- `href` equivalent to the `id` on the symbol -->
<use href="#symbol" x="0" y="0" width="20" height="30" />
</svg>

构建响应式SVG

在我们组合最终的SVG之前,让我们从涡旋元素开始,稍后我们将将其用作符号。

我首先创建了一个宽度为21、高度为25的画板,在上面绘制了一条螺旋线。我将路径宽度设置为2,并选择了圆形的起始点和结束点,以获得平滑的外观。为了确保对称性,我将曲线的起始点和结束点定位在它们的x坐标都为16的位置。

根据您使用的图形工具,导出设计后获得的SVG代码可能会有所不同。以下是我从Figma导出涡旋设计时的代码示例:

1
2
3
4
5
6
7
8
9
10
<svg width="21" height="25" viewBox="0 0 21 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_34_935)">
<path d="M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0" stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_34_935">
<rect width="21" height="25" fill="white"/>
</clipPath>
</defs>
</svg>

其中包含了很多不必要的内容。最终,我们只需要定义涡旋的路径。

Figma经常包含一个clipPath,在我们的小演示中是不需要的。手动移除了除了path标签之外的所有内容。

1
2
3
<svg width="21" height="25" viewBox="0 0 21 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="..." stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</svg>
1
2
3
<svg width="21" height="25" viewBox="0 0 21 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0" stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</svg>

准备好我们的涡旋图像后,我们就可以构建实际的SVG了。让我们将宽度设置为21(与涡旋相同的宽度),并初步将SVG的高度设置为80。正如我们之前讨论的,我们将省略viewBox属性。

在我们的SVG中,我们将在标签中将涡旋定义为一个符号。为了创建这个符号,我们可以使用我们创建的涡旋SVG的大部分代码。

主要的更改涉及将<svg>标签替换为<symbol>标签,并删除xmlns属性,因为对于符号而言这是不必要的。我们确实需要一个id,以便在use标签中引用它。

将其移到<defs>作为<symbol>将防止路径在内容中可见。

1
2
3
4
5
6
7
<svg width="21" height="80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="swirl" width="21" height="25" viewBox="0 0 21 25" fill="none">
<path d="..." stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</symbol>
</defs>
</svg>

为了使涡旋路径可见,我们必须插入一个标签,引用这个符号。这就是preserveAspectRatio属性发挥作用的地方。我们希望我们的涡旋始终对齐在SVG的底部,因此我们将preserveAspectRatio="xMidYMax"应用于符号。这确保了涡旋锚定在SVG的中底部。

此外,通过通过<use>中的引用将符号的高度设置为100%,我们确保它始终与SVG的高度匹配,可以灵活适应SVG尺寸的任何变化。

1
2
3
4
5
6
7
8
<svg width="21" height="80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="swirl-1" width="21" height="25" viewBox="0 0 21 25" preserveAspectRatio="xMidYMax" fill="none">
<path d="M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0" stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</symbol>
</defs>
<use href="#swirl-1" x="0" y="0" width="21" height="100%" />
</svg>

现在我们有一个SVG,其中的涡旋始终位于底部,而不管通过CSS进行的任何高度更改。

接下来,让我们添加那根长竖线,为此,我们将插入一个从顶部延伸到底部的矩形。通过将矩形的高度设置为100%,可以轻松实现这一点。

1
2
3
4
5
6
7
8
9
<svg width="21" height="80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="swirl-2" width="21" height="25" viewBox="0 0 21 25" preserveAspectRatio="xMidYMax" fill="none">
<path d="M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0" stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</symbol>
</defs>
<use href="#swirl-2" x="0" y="0" width="21" height="100%" />
<rect x="15" y="0" width="2" height="100%" rx="1" fill="#f09" />
</svg>

然而,实际上我们并不希望矩形的高度延伸到SVG的整个100%。理想情况下,它应该停在涡旋开始的地方。

SVG中,不能从底部定义坐标,但我们可以巧妙地使用CSS来实现所需的效果。通过将矩形的高度设置为100% - 24px,我们确保它仅达到涡旋的上方。这个调整可以直接在SVG的代码中进行。

width
1
2
3
4
5
6
7
8
9
10
11
12
13
	<style>
#swirl-4-rect {
height: calc(100% - 24px);
}
</style>
<defs>
<symbol id="swirl-4" width="21" height="25" viewBox="0 0 21 25" preserveAspectRatio="xMidYMax" fill="none">
<path d="M16 21.5C16 19.25 16 18.6 16 15C16 7 11.75 3 7.5 3C3.2503 3 2 6.5 2 8C2 9.5 3.2503 13 7.5 13C10.5 13 16 12 16 2V0" stroke="#FF0099" stroke-width="2" stroke-linecap="round"/>
</symbol>
</defs>
<use href="#swirl-4" x="0" y="0" width="21" height="100%" />
<rect id="swirl-4-rect" x="15" y="0" width="2" height="100%" rx="1" fill="#f09" />
</svg>

搞定了!我们成功地创建了一个响应式的SVG,它可以调整大小,同时始终保持漩涡循环位于底部,确保不会发生形变。

使用响应式SVG

现在,您可能想知道,我们实际上如何在代码中使用漩涡线呢?您有几种选择。

内联SVG

其中一种最简单的方法是将其用作内联SVG。此方法允许您仅在文档开头定义一次该符号,而不是多次重复。此外,SVG的样式定义可以包含在常规CSS样式表中。最好使用特定类应用这些样式,以避免全局影响所有矩形元素。

使用图像标签

您还可以将代码保存为SVG文件,然后使用图像标签。请注意,对于此方法,您必须从SVG中删除宽度和高度属性,而是将它们应用于<img>标签。

CSS中的SVG

也许最激动人心的选择是将SVG直接嵌入我们的CSS中作为数据URI背景图像。

为此,我推荐使用@yoksel的一个很棒的工具,该工具允许您简单地复制并粘贴任何SVG,并为您的样式表生成一个准备就绪的代码片段。然后,例如,您可以使用伪元素并应用背景图像。

这个过程实质上是在SVG中嵌入CSS,然后将其嵌入到您的CSS文件中。