基本形状和路径... 两者永远不能相容?

Avatar of Chris Coyier
Chris Coyier

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

CSS 中有一些值可用于绘制形状。例如,circle() 函数是几个 CSS 属性的有效值。不过,“绘制”可能不是合适的词。这与 SVG 中可以创建 <circle> 元素并字面意义上绘制一个圆圈不同。

CSS 中的这些形状用于其他用途。即:clip-path 用于制作剪切蒙版,shape-outside 用于使文本围绕形状流动。

还有一些其他 CSS 属性使用类似 SVG 的形状来执行其功能。例如,offset-path 是沿着矢量路径对元素进行动画处理的一部分,使用 path() 函数。路径很棒。它们是终极的绘图元素,因为它们 可以绘制任何内容,所有其他形状本质上都是路径的语法糖。

基本形状是什么?

有四个 基本形状

  • polygon()
  • circle()
  • ellipse()
  • inset()

路径是什么?

路径来自 SVG。它们具有 特殊的语法,允许它们绘制任何内容。

<path d="M 25,100 C 25,150 75,150 75,100 S 100,25 150,75" />
path("M 25,100 C 25,150 75,150 75,100 S 100,25 150,75");

事情变得有点奇怪

  • clip-pathshape-outside 属性可以采用所有“基本形状”,例如 circle()polygon(),但不能采用 path()
  • offset-path 属性可以采用 path(),但不能采用“基本形状”。
  • 您也可以通过 CSS 控制 <path>d 属性,但不能控制许多其他 SVG 元素的属性。

我不太确定为什么会出现这种情况,我相信随着时间的推移,情况会发生变化,但了解这一点很重要。

让我们详细说明。

clip-path 允许基本形状(但不允许 path()

假设您想将方形头像剪切成多边形,以获得有趣的图案。您可以做到!图像可能是 HTML 元素,例如

<img src="avatar.jpg" alt="User Avatar" class="avatar">
.avatar {
  clip-path: polygon(0% 5%, 100% 0%, 100% 85%, 65% 80%, 75% 100%, 40% 80%, 0% 75%);
}

查看 CodePen 上 Chris Coyier 的作品 剪切头像 (@chriscoyier)。

但是,假设您想像这样剪切头像

好吧,您做不到。至少不是直接用 CSS。这些曲线需要 path,而 clip-path 不支持 path。幸运的是,clip-path 可以采用 url(),它将接受 <clipPath> 元素的 ID。

查看 CodePen 上 Chris Coyier 的作品 剪切头像 (@chriscoyier)。

offset-path 允许 path(但不允许基本形状)

假设我们要沿着我们刚使用的那个气泡形状的外部移动一个对象。offset-path 属性专门用于此目的。

<div class="move-me"></div>
.move-me {
  offset-path: path("M100.5,39.47C100.5,58.3,83.36,74,60.58,77.64l16.85,19.9L33.94,76.25C14.47,70.92.5,56.47.5,39.47c0-21.52,22.39-39,50-39S100.5,17.95,100.5,39.47Z");
  animation: move 3s linear infinite;
}
@keyframes move {
  100% { motion-offset: 100%;}
}

查看 CodePen 上 Chris Coyier 的作品 path 上的 offset-path (@chriscoyier)。

但是,如果您想让元素在圆圈中移动怎么办?圆圈的基本形状版本具有非常简单的语法,例如 circle(50% at 50% 50%);但不幸的是,不支持基本形状。规范 允许它们,但它们不起作用。这有一定道理,因为... 您如何定义要移动的方向?

您仍然可以在圆圈中进行动画处理,因为功能强大的路径可以绘制圆圈,例如

.move-me {
  /* a circle */
  offset-path: path("M100,50a50,50,0,1,1-50-50A50,50,0,0,1,100,50Z");
  animation: move 3s linear infinite;
}
@keyframes move {
  100% { motion-offset: 100%;}
}

这些命令自然地指定了方向。还有一些 其他方法可以在圆圈中进行动画处理。

shape-outside 允许基本形状(但不允许 path()

假设您想让一些文本围绕蛋形包裹,因为... 我不知道,您正在设置一些爱丽丝对赫蒂·邓蒂的对话的文字。蛋形是使用 ellipse() 基本形状的一个好借口。

<div class="page-wrap">
  <div class="egg"></div>
  <p>"I don't know what you mean by 'glory,'" Alice said.</p>
  <p>Humpty Dumpty smiled contemptuously. "Of course you don't—till I tell you. I meant 'there's a nice knock-down argument for you!'"</p>

 ...
.egg {
  float: left;
  shape-outside: ellipse(120px 160px at 50% 50%);
  width: 280px;
  height: 320px;
}

我们可能会设置一个相同的 clip-path(以实际创建蛋形)并对其进行着色

查看 CodePen 上 Chris Coyier 的作品 形状外部蛋形 (@chriscoyier)。

但是,如果您想让一些文本围绕 *弯曲* 的形状包裹,就像这里在 Illustrator 中所示

Adobe Illustrator 中的文本环绕

不幸的是,shape-outside 不支持 path(),因此您无法做到。但您可以做到。它支持 url(),您可以使用它链接到图像(甚至不必是 SVG,但 SVG 很有意义)。图像可以具有一个漂亮的弯曲路径,就像我们想要的那样

查看 CodePen 上 Chris Coyier 的作品 围绕曲线环绕文本 (@chriscoyier)。

url() 甚至可以 成为数据 URL。还要注意,使用 shape-outside 的任何元素都必须 浮动,这可能是 CSS 排除 解决的限制。

<path> 采用 path()

这是一个开始时很有逻辑意义的例子。假设您有一条路径

<svg>
 <path d=" ... " />
</svg>

您可以通过 CSS 更改该路径的形状,例如通过悬停

svg:hover path {
  d: path(" ... ");
}

查看 CodePen 上 Chris Coyier 的作品 悬停时更改路径 (@chriscoyier)。

您甚至可以 过渡形状,如果它碰巧是具有相同点数的路径数据。

不过,它确实有点令人困惑。假设您有一个 <polygon> 而不是。

<svg>
 <polygon points=" ... " />
</svg>

您如何用 CSS 更新它?

polygon {
  /* Nope */
  points: " ... ";

  /* Nope */
  points: points(" ... ");

  /* Nope */
  points: polygon(" ... ");
}

据我所知,没有办法。这似乎很奇怪,因为 polygon 在其他地方都被支持。我想问题的一部分在于 polygon() 函数与 points 属性不同。polygon() 函数在 CSS 中使用百分比和带 *单位* 的数字,而 points 属性使用 *无单位* 数字(与 SVG 中的所有内容一样)。它们是不同的野兽,这种重叠很尴尬。

同样,与基本形状重叠的 SVG 形状也不能被更改。例如,<circle> 的所有属性都可以用 CSS 进行更改

svg:hover circle {
  cx: 40;
  cy: 40;
  r: 40;
}

查看 CodePen 上 Chris Coyier 的作品 更改圆形属性 (@chriscoyier)。

简而言之:通常有一种方法可以完成您想要完成的操作,但支持哪些功能以及不支持哪些功能很令人困惑。