Blob 是光滑、随机、果冻状的形状,具有异想天开的品质,而且非常有趣。它们可以用作 网页上的插图元素和背景效果。
那么,它们是如何制作的呢?只需打开一个插图应用程序,然后开始创作,对吧?当然,这很酷。但我们是在 CSS-Tricks 上发表的文章,所以用 CSS 和 SVG 这两种我们最喜欢的工具来探索可能性会更有意思!
实际上,我们有几种方法可以创建 Blob。让我们来试一试。
在 SVG 中绘制圆形
让我们从简单的开始。我们可以在 Illustrator、Sketch、Figma 或其他软件中绘制 SVG,但我们将直接在 SVG 代码中绘制。
由于 <circle>
元素的存在,在 SVG 中绘制圆形非常简单。
<circle cx="100" cy="100" r="40" fill="red" />
那些奇怪的属性?分解后就一目了然了。
cx
定义圆心在 x 轴上的坐标。cy
定义圆心在 y 轴上的坐标。r
是半径。fill
用于用颜色填充形状。
这段代码片段创建了一个半径为 40 像素的圆形,圆心在 x 轴上的坐标为 100 像素,在 y 轴上的坐标为 100 像素。坐标从父容器的左上角开始。
让我们创建多个这样的重叠圆形。
<svg height="300" width="300">
<circle cx="80" cy="80" r="40" fill="red" />
<circle cx="120" cy="80" r="40" fill="red" />
<circle cx="150" cy="80" r="40" fill="red" />
<circle cx="150" cy="120" r="40" fill="red" />
<circle cx="100" cy="100" r="40" fill="red" />
</svg>
<svg>
充当画板,所有不同的形状和图形都在上面绘制。因此,它的 height
和 width
指示整个绘图需要包含的大小。如果图形的一部分超出了 SVG 的大小范围,则该部分将被截断。
但是 Blob 并不总是那么完美地……圆形。我们可以使用 <ellipse>
来代替 <circle>
,从而打破这种模式。
<ellipse cx="200" cy="80" rx="100" ry="50" fill="red" />
这与圆形几乎完全相同,只是标签名称发生了变化,并且增加了两个半径值来分别定义水平 (rx
) 和垂直 (ry
) 半径。有趣的是,如果半径值相同,我们仍然可以得到一个完美的圆形。因此,在某种意义上,<ellipse>
更加通用。
而且,如果只需要一个圆形,我们可以直接使用 CSS,而无需 SVG。任何框元素都可以使用 border-radius
变成圆形或椭圆形。
.circle {
border-radius: 50%;
height: 50px;
width: 50px;
}
……但我们稍后再说。
使用 SVG 路径进行自由创作
借助 SVG 的 <path>
标签,我们可以创建任何形状。它就像用铅笔或钢笔绘画一样。您从一个点开始,然后画线、曲线、形状并闭合回路。
路径中有很多数据参数用于不同的任务,例如
M
– 移动到某个点L
– 绘制直线C
– 绘制曲线Q
– 贝塞尔曲线Z
– 闭合路径
Chris 有一篇 非常全面的指南,详细解释了这些参数。
我们只需要曲线 (C
) 参数来进行实际绘制。但我们也将移动起点并闭合路径,所以我们也会用到 M
和 Z
参数。

<path>
元素创建的随机 Blob 形状。准备分解它吗?坐标在 <path>
中起着重要作用,所以我们即将看到的内容看起来像是 Google 地图数据被吐进了我们的代码中。但当我们知道它们在做什么时,就会变得更有意义了。
比如这个……
<svg xmlns="http://www.w3.org/2000/svg">
<path
fill="#24A148"
d=""
/>
</svg>
在这里,d
属性存储路径数据。它包含绘制起点、移动方向、遵循形状以及结束位置的信息。例如
<path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
它显示我们的路径从坐标 10 10
开始,由前面的 M
表示。然后,它建立了一个 三次贝塞尔曲线 (C
),带有两个控制点。贝塞尔曲线就像路径两端的控制手柄,控制它们之间的弯曲程度。我们有两个贝塞尔“手柄”:一个用于曲线的起始位置 (20 20
),另一个用于曲线的结束位置 (40 20
)。

让我们利用这些知识来设计我们的 Blob。我绘制的 Blob 实际上有点复杂,包含许多曲线和控制点。很多坐标不是完整的整数,这更让情况变得复杂。但现在我们已经了解了 <path>
的 d
参数的作用以及它用于绘制路径上点的属性,它看起来并不那么可怕了。
但是,嘿,我理解。那么多代码不仅要手动编写,而且还要确保完全正确。我不会因为您使用 类似这样的工具来生成代码 而责怪您。
使用 CSS 和 SVG 滤镜实现果冻效果
SVG 路径很复杂。对吧?如果我向您展示一种将许多自定义形状(您可以通过 div 创建)转换为果冻 Blob 的方法呢?这就是想法。我们将创建两个相交的矩形。它们的颜色相同,但有一点透明度,以使相交处变暗。
然后,我们将利用 SVG 的模糊功能来模糊矩形,从而创建一个具有更柔和边缘的额外果冻 Blob。两个相交的矩形将变成这样 –

让我们首先了解 SVG 中的滤镜是如何工作的。它们是使用 <filter>
在 HTML 元素或其他 SVG 元素(如 circle
)上声明的。
circle {
filter: url("#id_of_filter");
}
<filter>
基本上是实际滤镜效果的包装器,其中包括
<feGaussianBlur>
<feImage>
<feMerge>
<feColorMatrix>
- 还有更多……请查看 此处 的完整列表。
我们的 Blob 是模糊的,而且有颜色,所以我们将使用 <feGaussianBlur>
和 <feColorMatrix>
。
<feGaussianBlur>
接受多个属性,但我们只关注其中两个:我们想要的模糊程度以及我们想要模糊的位置。标准差 (stdDeviation
) 和 in
属性分别与这些需求一致。
in
接受两个值之一
SourceGraphic
– 模糊整个形状SourceAlpha
– 模糊 alpha 值,用于创建阴影效果
经过一番尝试,我最终得到了 <feGaussianBlur>
效果
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
这可以直接放在 HTML 标记中,并使用一个 ID,我们在 Blob 的父元素中调用它。
<!-- The SVG filter -->
<svg style="position: absolute; width: 0; height: 0;">
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
</filter>
</svg>
<!-- The blob -->
<div class="hooks-main">
<div></div>
<div></div>
</div>
滤镜实际上不会渲染,即使它在标记中。相反,我们将它作为 Blob 父元素的 CSS 滤镜进行引用。
/* Blob parent element */
.hooks-main {
position: absolute;
width: 100%;
height: 100%;
filter: url("#goo&");
overflow: hidden;
}
这还没有完成。模糊是分散的,元素的形状失去了边界和颜色。我们需要一种凸出效果,在边界上模糊,并用纯色填充形状。这时,我们的下一个 SVG 滤镜 <feColorMatrix>
就发挥了作用。
我们想要使用 <feColorMatrix>
的两个属性
in
– 指示效果应用的位置,就像<feGaussianBlur>
一样。values
– 一个四行五列的矩阵。
values
属性稍微复杂一些。它包含一个矩阵,该矩阵将乘以每个像素的颜色和 alpha 值,并为该像素生成新的颜色值。从数学角度来说
new pixel color value = ( values matrix ) × ( current pixel color value )
让我们稍微深入一下数字。在那个方程中,values 矩阵
等于
[F-red1 F-green1 F-blue1 F-alpha1 F-constant1
F-red2 F-green2 F-blue2 F-alpha2 F-constant2
F-red3 F-green3 F-blue3 F-alpha3 F-constant3
F-red4 F-green4 F-blue4 F-alpha4 F-constant4]
这里,F-red
表示像素中红色部分的比例,取值范围为 0 到 1。F-constant
是要添加到颜色值(或从颜色值中减去)的某个常数值。
进一步分解……我们有一个颜色像素,其 RGBA 值为 rgba(214, 232, 250, 1)
。为了将其转换为新的颜色,我们将它乘以我们的 values
矩阵。
Values 矩阵 | 颜色像素 (RGBA) | 新颜色 (RGBA) | ||
---|---|---|---|---|
[1 0 0 0 0 | × | [214 | = [ 214x1 + 232x0 + 250x0 + 1x0 + 1x1 | = [214 |
像素值没有改变,因为我们将其乘以 单位矩阵,但如果您更改矩阵的值,则像素值也会发生变化。从 MDN 文档 中了解更多关于 values
矩阵的信息。
在我们这个案例中,这些值似乎很有效。
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
<feColorMatrix
in="blur"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 30 -7"
/>
</filter>
我在 Blob 中添加了一些其他样式,以将其从角落拉伸。
尝试将这些滤镜值应用于其他形状,并在评论中告诉我它们的效果。
使用 CSS border-radius
我们之前已经预告过,现在让我们来谈谈 CSS 的 `border-radius` 属性。它还可以创建水滴状形状,因为它可以平滑元素的角。这是因为每个角的半径被分成两个半径,每个边一个。这就是为什么除了圆形和椭圆形之外,我们还可以拥有更多形状。

你可能习惯于使用 `border-radius` 作为元素所有四个角的简写
.rounded {
border-radius: 25%;
}
这是一种让所有角都保持一致的好方法。但水滴状形状并不那么一致。我们希望有些角比其他角更圆,以便得到看起来像胶状的形状。这就是为什么我们要使用 `border-radius` 的组成属性,比如
.element {
border-top-left-radius: 70% 60%;
border-top-right-radius: 30% 40%;
border-bottom-right-radius: 30% 60%;
border-bottom-left-radius: 70% 40%;
}
并且看到每个属性都接受两个值?这分别对应于角的每个边,为我们提供了很大的灵活性,可以将元素弯曲成有趣的形状。然后,我们可以添加背景颜色,用渐变填充它,甚至在它上面设置一个 `box-shadow` 来获得一个整洁的效果。
不错!几个月前我尝试过在外面使用胶状效果,并创建了这个:https://jsfiddle.net/ashq26p8/4/
遗憾的是,它需要在容器周围设置相当宽的边框才能获得良好的效果,但是,它确实有效。
看起来很酷。我猜边框和盒子颜色需要相同。就像你在演示中使用黑色一样。