本文:

在 Firefox 62 版本中,CSS Shapes 正式发布,同时还增加了一个非常棒的 Firefox DevTools 工具,可以帮助我们更好地使用 Shapes。在本文中,Rachel Andrew 将深入探讨 CSS Shapes,以及如何使用图像、渐变和基本形状创建非矩形形状。我们还将了解 Firefox 中的新工具如何简化形状的编辑。

CSS Shapes Level 1 已经在 Chrome 和 Safari 中可用多年,而本周它随 Firefox 62 的发布一同到来,并且附带了增强的 Firefox DevTools 以便我们操作 Shapes。本文将介绍你可以使用 CSS Shapes 完成的一些事情。也许现在是时候考虑为你的设计添加一些曲线了?

什么是 CSS Shapes?

CSS Shapes 规范 Level 1 定义了三个新属性:

该规范的目的是允许内容围绕非矩形形状流动,这在我们的盒型 Web 上是非常不寻常的。创建形状的方法有几种,我们将在本教程中进行介绍。我们还将了解 Firefox 中可用的 Shape Path Editor,因为它可以帮助你轻松理解页面上的形状并使用它们。

在当前的规范中,形状只能应用于 float 元素,因此任何形状示例都需要从一个 float 元素开始。在下面的示例中,我有一个带有透明背景的 PNG 图像,我将该图像向左浮动。图像后面的文本现在将围绕图像的右侧和底部流动。

我希望发生的是,我的内容能够沿着图像不透明部分的形状流动,而不是沿着物理图像文件的线条流动。为此,我使用 shape-outside 属性,其值为我的图像的 URL。我正在使用实际的图像文件来创建一个内容流动的路径。

(这里会嵌入一个 CodePen 示例)

请注意,你的图像需要与 CORS 兼容,因此需要托管在与其余内容相同的服务器上,或者在托管在 CDN 上时发送正确的标头。如果你的图像由于 CORS 被阻止,浏览器 DevTools 通常会告诉你。

这种创建形状的方法使用图像的 Alpha 通道来创建形状,由于我们有一个具有完全透明区域的形状,那么我们所需要做的就是将图像的 URL 传递给 shape-outside,形状路径就会沿着完全不透明区域的线条。

创建边距

为了将文本行从图像推开,我们可以使用 shape-margin 属性。这会在形状的线条和与其并排运行的内容之间创建一个边距。

(这里会嵌入一个 CodePen 示例)

使用生成内容作为形状

在上面的例子中,我们在页面上显示了图像,然后文本围绕它弯曲。但是,你也可以使用图像作为形状的路径,以便创建弯曲的文本效果,而无需在页面上也包含该图像。但是,你仍然需要一些东西来浮动,因此,我们可以使用生成的内容。

(这里会嵌入一个 CodePen 示例)

在这个例子中,我们插入了一些生成的内容,将它向左浮动,给它一个宽度和高度,然后像之前一样使用带有图像的 shape-outside。然后,我们在空白处得到一条弯曲的线,但没有可见的图像。

使用渐变作为形状

CSS 渐变就像图像一样,这意味着我们可以使用渐变来创建形状,这可以产生一些有趣的效果。在下一个示例中,我创建了一个从蓝色到透明的渐变;你的渐变需要有一个透明或半透明的区域才能使用形状。我再次使用生成的内容来添加渐变,然后将渐变用作 shape-outside 的值。

一旦渐变变得完全透明,形状就会发挥作用,内容会沿着渐变的边缘运行。

(这里会嵌入一个 CodePen 示例)

使用 shape-image-threshold 将文本定位在半透明图像上

到目前为止,我们已经研究了使用图像或渐变的完全透明部分来创建形状,但是,CSS Shapes 规范中定义的第三个属性意味着我们可以通过设置阈值来使用具有半透明区域的图像或渐变。shape-image-threshold 的值为 1 表示完全不透明,而 0 表示完全透明。

像我们上面的示例这样的渐变是查看此操作的好方法,因为我们可以更改 shape-image-threshold 值并移动文本所在的行到更不透明的区域或更透明的区域。此属性的工作方式与具有 Alpha 通道但不完全透明的图像完全相同。

(这里会嵌入一个 CodePen 示例)

我认为这种从图像和渐变创建形状的方法是创建形状最直接的方法。你可以在图形应用程序中舒适地创建一个与你需要的复杂程度相同的形状,然后使用它来定义页面上的形状。也就是说,还有另一种创建形状的方法,那就是使用 Basic Shapes

使用 Basic Shapes 的 CSS Shapes

Basic Shapes 是一组预定义的形状,涵盖了你可能想要创建的许多不同类型的形状。要使用基本形状,请使用基本形状 type 作为 shape-outside 的值。此类型使用函数表示法,因此我们有形状的名称,后跟括号(括号内是我们形状的一些值)。

你可以使用的选项如下:

我们将首先看一下 circle() 类型,因为我们可以使用它来理解一些适用于所有使用基本形状类型的形状的有用知识。我们还将了解 Firefox 中用于检查这些形状的新工具。

在下面的例子中,我创建了最简单的形状:使用 shape-outside: circle(50%) 创建一个圆。我再次使用生成的内容,并且我给了盒子一个背景颜色,还添加了一个边距、边框和内边距,以帮助突出显示使用 CSS Shapes 的一些概念。你可以在示例中看到圆是如何在盒子的中心创建的;这是因为我给了圆一个 50% 的值。该值是 <shape-radius>,它可以是长度或百分比。我使用了百分比,因此半径是我盒子大小的一半。

(这里会嵌入一个 CodePen 示例)

现在是时候使用 Firefox Shape Path Editor 查看已创建的形状了。你可以通过单击生成的内容,然后单击属性 shape-outside 旁边的小形状图标来检查该形状;你的形状现在将突出显示。

你可以看到圆是如何延伸到我们盒子上边距的边缘的。这是因为我们的形状使用的初始 reference boxmargin-box。如果你曾经将 box-sizing: border-box 添加到你的 CSS 中,你已经知道了一些关于 reference boxes 的知识。当你这样做时,你要求 CSS 使用 border-box 而不是默认的 content-box 作为元素的大小。在 Shapes 中,我们也可以更改使用哪个 reference box。在任何基本形状之后,添加 border-box 以使用边框定义形状,或添加 content-box 以使用内容边缘(在内边距内)。例如:

.content::before {
  content: "";
  width: 150px;
  height: 150px;
  margin: 20px;
  padding: 20px;
  border: 10px solid #FC466B;
  background: linear-gradient(90deg, #FC466B 0%, #3F5EFB 100%);
  float: left;
  circle(50%) content-box;
}

你会看到圆看起来变小了很多。它现在使用内容的宽度——在本例中是盒子在 150px 处的宽度——而不是包括内边距、边框和外边距的边距框。

在 Firefox DevTools 中检查你的元素也会显示 reference boxes,因此你可以选择哪个可能为你提供特定形状的最佳结果。

Position 值

可以传递给 circle() 的第二个值是位置;如果你不传递此值,则默认为 center。但是,你可以使用此值来移动你的圆。在下一个示例中,我使用 shape-outside(50% at 30%) 定位了圆;这会更改圆心的位置。

(这里会嵌入一个 CodePen 示例)

clip-path

要知道的有用的一点是,相同的 <basic-shape> 值可以用作 clip-path 的值。这意味着在创建形状后,你可以剪掉延伸到形状外部的图像或背景颜色。在下面的示例中,我将使用我们的示例渐变背景来执行此操作,以便我们最终得到一个圆,该圆的文本从我们的正方形框弯曲。

(这里会嵌入一个 CodePen 示例)

以上所有概念都可以应用于我们的其他基本形状。现在让我们快速了解一下它们是如何工作的。

inset()

inset() 值定义一个矩形。这似乎不是很有用,因为浮动是一个矩形,但是,此值意味着你可以插入环绕形状的内容。它采用四个值:上、右、下和左,外加一个定义边框半径的最终值。

在下面的示例中,我使用这些值来插入浮动图像右侧和底部的内容,并添加一个边框半径,我的内容将使用 shape-outside: inset(0 30px 100px 0 round 40px) 环绕该边框半径。你可以看到内容现在是如何位于盒子的背景颜色之上的:

(这里会嵌入一个 CodePen 示例)

ellipse()

椭圆是一个被压缩的圆,因此需要两个半径,分别用于 x 和 y(按此顺序)。然后你可以像使用位置值移动圆一样移动椭圆。在下面的示例中,我创建了一个椭圆,然后使用具有相同值的 clip-path 移除形状外部的内容。

(这里会嵌入一个 CodePen 示例)

在上面的示例中,我还使用了 shape-margin 来演示如何像使用图像生成的形状一样使用此属性来推开内容。

polygon()

创建多边形形状为我们提供了最大的灵活性,因为我们的形状可以使用三个或更多点创建。传递给多边形的值需要是三对或更多对代表坐标的值。

在这里,Firefox 工具变得非常有用,因为我们可以使用它们来帮助创建多边形。在下面的示例中,我创建了一个具有四个点的多边形。在 Firefox DevTools 中,你可以双击任何线以创建一个新点,然后再次双击以将其移除。创建好你满意的多边形后,你可以将该值从 DevTools 中复制出来用于你的 CSS。

(这里会嵌入一个 CodePen 示例)

Fallbacks

由于 CSS Shapes 应用于 float 元素,因此在许多情况下,fallback 是看到内容环绕 float 元素(就像内容一直环绕 float 元素一样),而不是看到内容环绕一个形状。浏览器会忽略它们不理解的属性,因此如果它们不理解 Shapes,那么 shape-outside 属性是否存在就无关紧要了。

你应该注意的情况是,如果缺少形状可能意味着内容覆盖了一个难以阅读的区域。例如,你可能正在使用 Shapes 将内容从背景图像的繁忙区域推开。在这种情况下,你首先应该确保你的内容对于不支持 Shapes 的访问者可用,然后使用 Feature Queries 检查对 shape-outside 的支持并覆盖该 CSS 并应用该形状。例如,你可以使用边距将内容推开给不支持 Shapes 的访问者,并在你的 feature query 中删除该边距。

.content {
  margin-left: 120px;
}
@supports (shape-outside: circle()) {
  .content {
    margin-left: 0;
    /* add the rest of your shapes CSS here */
  }
}

随着 Firefox 发布他们的支持,我们现在只有一个主要浏览器不支持 Shapes - Edge。

查找更多关于 CSS Shapes 的信息

在本文中,我试图快速概述一些使用 CSS Shapes 可以实现的有趣的事情。有关每个功能的更深入的了解,请查看 MDN 上的 CSS Shapes 指南。你还可以阅读 Firefox 中 Shape Path Editor 的指南