使用“rect”元素为SVG添加背景颜色

Avatar of Kate Holterhoff
Kate Holterhoff

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元免费积分!

使用 SVG 的优点在网页开发中 众所周知。SVG 的大小很小,可以制作得非常易于访问,在保持质量的同时可扩展,并且可以进行动画处理。不过,也存在学习曲线。例如,SVG 语法可能有点棘手,有时需要手动修改 SVG 代码。

大多数 SVG 资源允许以可预测的方式应用样式。例如,这个圆圈有一个悬停状态,其功能与 DOM 中的任何其他元素非常相似。

但是,我在多个前端项目中遇到的一个问题是,客户、设计师或品牌资源网站提供的 SVG 资源是 **次优的**。这些文件本身没有错误,但 SVG 代码需要手动修改才能实现必要的功能。与其请求新文件,不如我自己修改它们更容易。

由于 SVG 作为基于 XML 的文件,在某些方面类似于 HTML,但在其他方面则有所不同,因此为 SVG 设置样式很复杂。让我们以 Instagram 自身提供的示例 Instagram(也 很容易在维基百科上找到)为例。由于路径之间的空格充当一种透明度,因此该图像会显示应用在其后面的任何背景。

为什么 SVG 上没有背景颜色,这样我们就可以在悬停时应用颜色更改(例如 svg:hover { background: #888; })?这是因为路径填充了您认为它们应该填充的空间的反面。负空间会呈现该元素后面的任何内容(下面 CodePen 示例中的 <body>)。通常情况下,这不是问题,甚至可能是大型背景设计所希望的,以确保内容区域之间的自然过渡。但是,由于我将此 SVG 用作链接,因此需要更改该文件,以便可以设置其后面的空间的样式。

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  <title>Instagram</title>
  <path d="..." transform="translate(0 0)" fill="#fff"/>
  <path d="..." transform="translate(0 0)" fill="#fff"/>
  <path d="..." transform="translate(0 0)" fill="#fff"/>
</svg>

Instagram 徽标是一个完美的例子,它是一个需要比大多数 SVG 文件更精细的 CSS 的笨拙的 SVG 文件。再说一次,这个 SVG 没有什么 _错误_,但它在设置样式方面带来了一些挑战。为了添加一个更改背景的悬停状态,我们需要更改上面的代码。

有多种方法可以解决这个问题,但最简单的解决办法是在图像后面添加另一个元素。由于 Instagram 图标是矩形的,因此可以在构成此 SVG 的三个前景路径后面添加一个 <rect> 元素。如果徽标是圆形或椭圆形,我会使用 <circle><ellipse> 元素。添加此类元素时,请确保设置与 viewBox 相匹配的高度和宽度,并使用 rx 值根据需要圆角。与其在 SVG 元素中的每个路径中添加类或填充,不如在 CSS 文件中直接定位 <rect><path> 元素。

这种方法的优点在于它的简单性。无需更改多个文件或使用 JavaScript 或第三方 JavaScript 库,我们只需在 SVG 代码块中添加一行代码并设置其样式。

如果出于某种原因,您需要或更喜欢保持 SVG 文件不变,则可以修改 CSS 以实现类似的功能。

我们可以在 social-link 类上添加一个 background 属性,但是对于本教程,我将使用稍微复杂但同样有效的策略,即通过向 SVG 应用伪元素来修改 SVG。在下面的示例中,我使用了 ::before 伪类来添加形状,并使用 opacity 属性使其在悬停时可见。为了避免此形状在图标周围留有边框,我使用 heightwidth 属性(calc(100% - 2px))使它比 SVG 小一点。然后,我将伪元素居中放在 SVG 后面,并匹配元素和伪元素的过渡属性。

/* Sets the link's dimensions */
.social-link {
  display: block;
  height: 24px;
  position: relative;
  width: 24px;
}

/* Targets the pseudo-element to create a new layer */
.social-link::before {
  background: #fff;
  border-radius: 2px;
  content: "";
  display: block;
  height: calc(100% - 2px);
  opacity: 0;
  position: absolute;
  transition: all 0.2s ease-in-out;
  width: calc(100% - 2px);
}

/* Changes the background color of the pseudo-element on hover and focus */
.social-link::before:hover, .social-link::before:focus {
  background: #000;
}

/* Makes sure the actual SVG element is layered on top of the pseudo-element */
.social-link svg {
  position: relative;
  z-index: 1;
}

/* Makes the background-color transition smooth */
.social-link svg path {
  transition: all 0.2s ease-in-out;
}

/* SVG paths are initially white */
.social-link path {
  fill: #fff;
}

/* The pseudo-elememt comes into full view on hover and focus */
.social-link:hover::before, .social-link:focus::before {
  opacity: 1;
}

/* Fills the SVG paths to black on hover and focus  */
.social-link:hover svg path, .social-link:focus svg path {
  fill: #000;
}

我建议使用上述策略进行快速修复,因为在大多数情况下,使用原生 JavaScript 或像 vivus.jsraphaeljs 这样的 JavaScript 库来为 SVG 添加悬停状态有点大材小用。但是,有时使用 JavaScript 修改 SVG 是更好的选择。由于 JavaScript 无疑是更改样式最灵活的方法,让我们来看看这可能是什么样子。

我的示例将 JavaScript 文件分开了,但如果要将 JavaScript 添加到 SVG 元素本身,则需要添加一个 <script> 元素,就像 HTML 文件一样。请确保在 <script> 元素中添加 CDATA 标记,以确保它被解析为 XML。

我正在使用 jQuery 来简化操作,并尽可能减少 CSS 的使用,尽管为了清晰起见,我在 CSS 文件中为 social-link 类添加了一个 background 属性,而不是通过 JavaScript 添加。请注意,此解决方案在更改 CSS 方法时针对的是 svg path,而不是为这些路径分配类,因为在这种情况下,每个路径都应以相同的方式处理。

为 SVG 设置样式的方法有很多,但这篇文章中收集的示例非常有用且可扩展。修改 SVG 文件的策略需要根据应用程序的全部功能进行评估,但我怀疑大多数前端开发人员会发现 <rect> 元素提供了最简单、最易读的解决方案。

致谢

非常感谢 Joe Essey 和我在 Nebo Agency 的前端伙伴 Allison LewisNile Livingston(查看 Nile 的文章 “适用于 Web 的 SVG”)。