在上一篇文章中,我们使用了现代CSS特性如mask
、三角函数和CSS变量来创建类似花朵的形状。
HTML代码仅使用了一个元素,这意味着我们可以将CSS应用到图片元素上,获得类似下面演示的酷炫边框效果:
在本文中,我们将使用新的shape()
函数重新实现相同形状,我认为这会成为我最喜欢的CSS特性。
当前撰写时,只有Chrome、Edge和Safari完全支持我们使用的这些特性。
什么是 shape()?
你可能对clip-path: polygon()
很熟悉,对吧?这个函数允许你指定不同点,用直线连接它们并创建各种CSS形状(我邀请你查看我的CSS形状在线集合,看看其中的一些示例)。我说的是“直线”,因为说到曲线时,clip-path
功能非常有限。我们有circle()
和ellipse()
,但无法用它们实现复杂形状。
shape()
是克服这种限制的新值。除了直线,它还允许我们绘制曲线。但如果你查看MDN页面或规范,会发现语法有点复杂且难以掌握。它非常类似于SVG路径,这很好,因为它给了我们很多选项和灵活性,但需要大量练习才能熟练掌握。
我不会写一个枯燥的教程来解释语法和所有可能的值,而是专注于每篇文章的一个命令。本文我们将研究arc
命令,下一篇文章将介绍curve
命令。当然,我们还会绘制酷炫的形状,否则就没什么意思了!
arc 命令
这个命令允许你在两个点之间绘制椭圆弧,但我会只考虑圆的特殊情况,因为这更容易且你最可能需要。让我们从一些几何知识开始,理解其工作原理。
如果你有两个点(A和B)和一个半径,恰好有两个圆会经过这两个点。两个圆的交集为我们提供了4种可能的弧线,可以通过大小(小或大)和方向(顺时针或逆时针)来区分。
代码看起来如下:
clip-path: shape(from Xa Ya, arc to Xb Yb of R [large or small] [cw or ccw])
形状的第一个命令始终是from
来指定起点,然后使用arc
定义终点、半径、大小和方向。
这是一个演示不同值的示例:
这里我只改变大小和方向来选择四种可能性之一。需要注意的是,大小和方向不是必填项,默认值是small
和ccw
。
这就是我们绘制花朵形状所需的一切!
创建花朵形状
我将从上一篇文章中的图形开始。
使用遮罩方法,我们需要在中心绘制一个大圆和周围放置小圆。使用shape()
时,需要绘制小圆的弧线。每个弧线的起点和终点位于圆相交的位置。
代码如下:
.flower {
clip-path: shape(from X0 Y0,
arc to X1 Y1 of R,
arc to X2 Y2 of R,
arc to X3 Y3 of R,
arc to X4 Y4 of R,
...
arc to Xn Yn of R
)
}
像之前使用遮罩方法一样,我会依赖Sass来创建循环。
$n: 10;
.flower {
$m: ();
$m: append($m,from X0 Y0,comma);
@for $i from 1 through $n {
$m: append($m,arc to Xi Yi of R,comma);
}
clip-path: shape(#{$m});
}
现在我们需要确定小圆的半径(R)和各点的位置(Xi, Yi)。我在上一篇文章中已经计算了半径值,所以直接复用:
R = 50%/(1 + 1/math.sin(180deg/$n))
对于点的位置,它们位于同一圆周上,坐标可以表示为:
Xi = 50% + D*math.cos($i*360deg/$n)
Yi = 50% + D*math.sin($i*360deg/$n)
这里D和R的距离值如下:
D = 50%/(math.tan(180deg/$n) + 1/math.cos(180deg/$n))
最终代码如下:
$n: 10;
.flower {
$m: ();
$r: 50%/(1 + 1/math.sin(180deg/$n));
$d: 50%/(math.tan(180deg/$n) + 1/math.cos(180deg/$n));
$m: append($m,from
50% + $d*math.cos(0)
50% + $d*math.sin(0),comma);
@for $i from 1 through $n {
$m: append($m,arc to
50% + $d*math.cos($i*360deg/$n)
50% + $d*math.sin($i*360deg/$n)
of $r,comma);
}
clip-path: shape(#{$m});
}
我们没有定义弧线的大小和方向,因此浏览器会默认使用small
和ccw
,这会得到花朵的倒置版本。尝试四种组合(包括默认值)会得到以下效果:
small ccw
和large cw
会得到我们想要的形状。small cw
是一个有趣的变体,large ccw
则很有趣。我们可以使用CSS变量轻松控制想要的形状。
结合两种形状
现在看看下面的形状:
想法是使用相同代码并交替两种弧线配置:
$n: 10;
.flower {
$m: ();
$r: 50%/(1 + 1/math.sin(180deg/$n));
$d: 50%/(math.tan(180deg/$n) + 1/math.cos(180deg/$n));
$m: append($m,from
50% + $d*math.cos(0)
50% + $d*math.sin(0),comma);
@for $i from 1 through $n {
$c:small ccw;
@if $i % 2 == 0 {$c:large cw}
$m: append($m,arc to
50% + $d*math.cos($i*360deg/$n)
50% + $d*math.sin($i*360deg/$n)
of $r $c,comma);
}
clip-path: shape(#{$m});
}
我引入了一个新变量$c
,在循环中当$i
为奇数时取small ccw
,否则取large cw
。
优化代码
我们创建了一个通用代码,通过控制弧线大小/方向即可获得任何形状变体,但针对特定情况可以简化代码。
对于倒置变体(small ccw
),D
值可以替换为50%
,这会简化公式并扩大形状覆盖区域。同时需要更新半径值:
$n: 10;
.flower {
$m: ();
$r: 50%*math.tan(180deg/$n);
$m: append($m,from
50% + 50%*math.cos(0)
50% + 50%*math.sin(0),comma);
@for $i from 1 through $n {
$m: append($m,arc to
50% + 50%*math.cos($i*360deg/$n)
50% + 50%*math.sin($i*360deg/$n)
of $r,comma);
}
clip-path: shape(#{$m});
}
对于主形状,这次可以简化半径值并使用1%
:
$n: 10;
.flower {
$m: ();
$d: 50%/(math.cos(180deg/$n)*(1 + math.tan(180deg/$n));
$m: append($m,from
50% + $d*math.cos(0)
50% + $d*math.sin(0),comma);
@for $i from 1 through $n {
$m: append($m,arc to
50% + $d*math.cos($i*360deg/$n)
50% + $d*math.sin($i*360deg/$n)
of 1% cw,comma);
}
clip-path: shape(#{ $m });
}
这个例子很有趣,因为使用1%
作为半径看起来有点奇怪且不直观。在弧线命令的解释中,我提到两个点之间恰好有两个圆,但如果半径小于两点间距离的一半,就无法满足条件。这种情况下浏览器会自动调整半径直到找到满足条件的圆(这在规范中有定义)。这种圆的半径会等于两点间距离的一半,此时small
和large
将变得相同。
换句话说,指定小半径(如1%
)相当于让浏览器自动计算半径值(一种懒人但聪明的做法)。这个技巧在某些情况下可能不适用,但在很多场景下很有用,不要忘记它。
结论
本文就到这里!你应该已经掌握了arc命令的使用方法。我只研究了绘制圆形弧线的特殊情况,但一旦熟悉了这个方法,就可以尝试椭圆弧线,不过我认为你很少会用到它们。
最后用一个心形示例结束,这里我使用了arc命令。在查看我的代码前,你能自己想出如何实现吗?

優(yōu)網(wǎng)科技秉承"專業(yè)團隊、品質(zhì)服務(wù)" 的經(jīng)營理念,誠信務(wù)實的服務(wù)了近萬家客戶,成為眾多世界500強、集團和上市公司的長期合作伙伴!
優(yōu)網(wǎng)科技成立于2001年,擅長網(wǎng)站建設(shè)、網(wǎng)站與各類業(yè)務(wù)系統(tǒng)深度整合,致力于提供完善的企業(yè)互聯(lián)網(wǎng)解決方案。優(yōu)網(wǎng)科技提供PC端網(wǎng)站建設(shè)(品牌展示型、官方門戶型、營銷商務(wù)型、電子商務(wù)型、信息門戶型、微信小程序定制開發(fā)、移動端應(yīng)用(手機站、APP開發(fā))、微信定制開發(fā)(微信官網(wǎng)、微信商城、企業(yè)微信)等一系列互聯(lián)網(wǎng)應(yīng)用服務(wù)。