假设有人要求您向一些随机的几何 SVG 形状添加一个**双**边框。由于某种原因,您无法使用任何图形编辑器——它们需要在运行时生成——因此您必须使用 CSS 或在 SVG 语法中解决它。
您的第一个问题可能是:SVG 中是否有类似于
好吧,答案是还没有,而且并不容易。但我还是会尝试一下,看看我能发现什么方法。我将探索三种不同基本形状的可能性:圆形、矩形和多边形。指出哪些可以在两条线中间保持透明颜色。stroke-style: double
的东西?
**剧透警告:**所有结果都有其缺点,至少在 CSS 和 SVG 中是这样,但让我带您了解我的意图。
简单的解决方案
这些不适用于所有形状,但它们是最简单的解决方案。
outline
和 box-shadow
CSS 属性outline
和box-shadow
仅适用于形状或 SVG 的边界框,因此两者都是仅适用于正方形和矩形的极佳解决方案。它们还允许使用自定义属性灵活地使用颜色。
使用outline
只需两行 CSS 代码,并且它可以使背景颜色通过形状可见。
- 🙁 仅适用于一种形状的解决方案。
- ✅ 代码简单
- ✅ 边界平滑
- ✅ 透明背景
box-shadow
只需要一行 CSS 代码,但我们必须确保每个形状都有自己的 SVG,因为我们无法直接将box-shadow
应用于形状。需要考虑的另一件事是,我们必须在声明中应用背景颜色。
- 🙁 仅适用于一种形状的解决方案
- ✅ 代码简单
- ✅ 边界平滑
- 🙁 没有透明背景
SVG 渐变
SVG 径向渐变仅适用于圆形☺️。我们可以直接将渐变应用于描边,但最好使用变量,因为我们必须在代码中多次声明颜色。
- 🙁 仅适用于一种形状的解决方案
- ✅ 代码简单
- 🙁 边界平滑
- 🙁 没有透明背景
所有形状的解决方案
这些将适用于所有形状,但代码可能会变得臃肿或复杂。
filter:
drop-shadow()
终于,一个适用于所有形状的解决方案!我们必须将每个形状都放在它自己的<svg>
中,因为filter
不会直接应用于形状。我们在 CSS 中使用一个声明,并使用变量灵活地使用颜色。缺点?边框看起来不太平滑。
- ✅ 一种适用于所有形状的解决方案
- ✅ 代码简单
- 🙁 边界看起来像素化
- 🙁 没有透明背景
SVG 过滤器
这是一个非常灵活的解决方案。我们可以创建一个过滤器,并通过 SVG 的filter
属性将其添加到形状中。这里复杂的部分是过滤器本身。我们需要三张图画,一张用于外部边框,一张用于背景填充,最后一张用于在前面绘制形状。结果看起来比使用drop-shadow
更好,但边框仍然是像素化的。
- ✅ 一种适用于所有形状的解决方案
- 🙁 代码复杂
- 🙁 边界看起来像素化
- 🙁 没有透明背景
重用形状
这里有几个可能的选择。
选项 1:变换
此解决方案需要变换。我们将一个图形放在另一个图形之上,其中主图形具有填充颜色和描边颜色,而另一个图形没有填充,具有红色描边,并缩放并重新定位到中心。我们在<defs>
中定义了我们的形状。诀窍是将viewBox
的一半转换为负空间,这样,当我们缩放它们时,就可以从图形的中心进行缩放。
- ✅ 一种适用于所有形状的解决方案
- 🙁 代码重复
- ✅ 边界平滑
- ✅ 透明背景
<use>
选项 2:我在 Doug Schepers 的www-svg 邮件列表中发现了一个巧妙的解决方案,该方案使用了 SVG <use>
。同样,它需要先定义形状,然后使用 <use> 两次引用它们。这次主形状具有更大的描边。第二个形状具有主形状的一半描边,没有填充,并且描边与背景颜色匹配。
- ✅ 一种适用于所有形状的解决方案
- 🙁 代码重复
- ✅ 边界平滑
- 🙁 没有透明背景
以下是完整的结果!
这样您就可以将它们全部放在一个地方。如果您能想到其他可能的解决方案,请告诉我!
解决方案 | 所有形状 | 代码简单 | 边界平滑 | 透明背景 |
---|---|---|---|---|
outline | 🙁 | ✅ | ✅ | ✅ |
box-shadow | 🙁 | ✅ | ✅ | 🙁 |
SVG 渐变 | 🙁 | ✅ | 🙁 | 🙁 |
filter: drop-shadow() | ✅ | ✅ | 🙁 | 🙁 |
SVG 过滤器 | ✅ | 🙁 | 🙁 | 🙁 |
重用形状 变换 | ✅ | 🙁 | ✅ | ✅ |
重用形状<use> | ✅ | 🙁 | ✅ | 🙁 |
还有另一种方法:“使用蒙版重用”。我相信它至少会满足您的标准并获得三个绿色勾号。
顺便说一句,我不同意“重用形状”方法不是“简单代码”。您是否认为它复杂是因为它使用了
<use>
元素?如果您觉得<use>
太令人困惑,您始终可以重复该元素。我真的很喜欢这种方法,我尝试过使用“蒙版”,但没有得到任何结果,现在我明白了自己错过了什么 :)
嗯,是的,我承认“简单代码”相当主观,我当时在想您需要先声明形状然后重复使用“use”的方式。对我来说,在 SVG 中只有一个形状在某种程度上更简单。
我来到评论区是为了提供Paul LeBeau已经发布的解决方案——我现在不会再提了——并指出转换方法的一个问题。它实际上并不适用于所有形状。以下是一些示例。尝试使用一个宽度远大于高度的矩形或椭圆,您会看到第二个轮廓在顶部和底部过于靠近原始轮廓。更复杂的形状,例如字母P、新月形或马萨诸塞州,肯定会有一些地方第二个轮廓在原始轮廓的错误一侧。
形状的外部只是该形状更大副本的这种谬误相当普遍,我见过它导致了一些难看的图形(包括路标,遗憾的是)。
说得对,我没有考虑到这些形状,转换选项在那里不起作用。感谢您指出这一点!