以下是Ryan Scherf的来宾帖子。 瑞安(Ryan)找到了一种巧妙的方法来赋予化身某种粗糙,不均匀,变化的边缘。 有点像不太熟练使用剪刀的人用剪刀将它们剪掉。 好的是,它自然是一种渐进增强技术,可以仅通过CSS来完成。
对于像Quirky这样的富有创造力和乐趣的品牌,我们一直在思考将这种氛围引入网络的方法。 在整个站点中,某些元素都有“手绘”外观。 如果不使用大量图像,则很难获得手绘效果。 有了一些光三角学和CSS的clip-path
非常基础的知识,我们就可以相对轻松和良好地做到这一点。
为什么不使用图像蒙版?
例如,在SVG中定义的遮罩:
img {
mask: url(mask.svg) top left / cover;
}
mask
属性可以通过ID引用文档中定义的外部SVG或SVG。
但是,如果您希望为每个显示的化身使用唯一的形状而不是相同的形状呢? 您可以以编程方式生成许多不同的SVG形状以进行应用。 但是,我们可以通过使用(S)CSS生成clip-path
s来实现同一目的并获得数学生成。
浏览器支持什么?
与形状值(例如polygon()
一起使用时,浏览器对clip-path
支持为Chrome 24 +,Safari 7 +,Opera 25 +,iOS 7.1 +,Android 4.4+。 Firefox仅使用SVG中定义的路径支持clip-path
(我们将对此进行介绍)。 IE中尚无支持。
您将需要使用-webkit-clip-path
,因为这是目前唯一支持的方式,但是最好也将clip-path
放在那里。 如果IE或Firefox开始以这种方式支持它,则可能没有前缀。
简而言之剪切路径
您可以将一些不同的形状值用于CSS剪切,但在我们的示例中, polygon
形状是最好的,因为它可以为我们提供最多的点数和灵活性,以创建手绘效果。
您可以为polygon()
提供X,Y点值的列表,例如: <x0> <y0>, <x1> <y1>, ... <xn> <yn>
。 这将在您的点周围绘制一条路径,以便在新创建的形状之外裁剪所有内容。
/*
This will create a Hexagon, with the first
point being the top tip of the shape
*/
.hexagon {
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
}
这是运行中的简单示例:
在CodePen上查看 Chris Coyier ( @chriscoyier )的带剪切路径的Pen Hexagon 。
不那么吓人的数学
我们的六边形很酷,但是还没有达到真正的粗略效果。 相当僵化–行太少。 想到手绘形状的最佳方法是连接两个点的一系列细线。 我们拥有的点越多,我们创建的短线越多。 实际上,只要有足够的点,我们就可以使polygon
形状如此平滑以至于模仿一个circle
。
这是使用200点的示例:
在CodePen上查看 Chris Coyier ( @chriscoyier )的“笔200点” 。
积分从何而来?
这是一点数学的地方。也许您在高中学习了三角学? 您在那堂课上学到的基本思想之一是关于单位圈 。 基本上,有一个设置公式(给定pi),可以在一个圆周围生成任意数量的点。
如果我们要连接各段,则会得到一个看起来像这样的形状:
仍然有些僵化,但看起来也有些手绘。
更多积分!
我们知道如何使用clip-path: polygon()
制作六边形和圆形,那么如何使其看起来像手绘的呢?
- 调整点数(数量越多,线段长度越短)
- 添加一些X和Y方差(因此各段不统一)
让我们将其引入SCSS并创建一个函数来为我们完成肮脏的工作。 我们将使用:
-
random()
-
cos()
-
sin()
最相关的数学是:
/*
To generate an arbitrary points on
the unit circle at angle t
*/
$x: cos(t);
$y: sin(t);
并以正确的语法显示如下:
$w: 160px // Avatar width
$n: 60; // Number of points on the circle
@function sketchAvatar() {
$points: ();
@for $i from 0 through $n {
$points: append($points, ($w / 2) * (1 + cos((2 * pi() * $i / $n))) ($w / 2) * (1 + sin((2 * pi() * $i / $n))), comma);
}
@return $points;
}
这有点毛。 发生的情况是,我们从形状的顶部中间开始,并为60个均匀间隔的点生成了围绕圆的点集列表。
将其与差异一起
上面的代码仍然产生平淡而均匀的多边形,因此我们必须添加方差。 我们需要做的就是在任何方向上调整点,以提供我们正在寻找的偏移感。 $lower
和$upper
方差数几乎可以取决于您要使用的外观。
$w: 120px; // Overall width
@function sketchAvatar() {
$n: 60; // Number of points
$lower: -80; // Lower variance
$upper: 80; // Upper variance
$points: ();
@for $i from 0 through $n {
$points: append($points, ($w / 2) * (1 + cos((2 * pi() * $i / $n))) + (rand($lower, $upper) / 100) ($w / 2) * (1 + sin((2 * pi() * $i / $n))), comma);
}
@return $points;
}
我们做到了! 粗略,独特的头像,带有CSS clip-path: polygon()
:
见钢笔手绘头像由克里斯Coyier( @chriscoyier上) CodePen 。
使它在Firefox中工作
克里斯在这里! 我认为,由于Firefox不支持这种方式,但确实支持SVG语法,因此我们可以将其填充。
.avatar {
clip-path: polygon( ... ) /* Firefox: nope */
clip-path: url(#clip); /* Firefox: yep */
}
所以对于每个化身,我……
- 在CSS中的伪元素(具有有效伪元素的元素,如父div的元素)的content属性中输出多边形点
- 使用JavaScript提取该值
- 重新格式化点以匹配SVG格式(例如,没有“ px”)
- 在路径上注入一个新的
<svg>
并准备好使用<clipPath>
$(".user").each(function(i) {
var path = window.getComputedStyle(this, ':after').getPropertyValue('content');
// clean house
svgPolygonPoints =
path
.replace(/px/g, "")
.replace(/polygon/, "")
.replace(/\(/, "")
.replace(/\)/, "")
.replace(/\;/g, "")
.replace(/"/g, "")
.replace(/\'/g, "");
// To get this to actually work, create a <div> instead with this inside, see below.
var svg = $("<svg width='0' height='0'>")
.append("<defs><clipPath id='clip-" + (i+1) +"'><polygon points='" + svgPolygonPoints +"' /></clipPath></defs>");
$("body").append(svg);
});
没用! 哈哈。 即使您在化身上强制重画,由于某种原因,它也不喜欢注入的SVG。 查看Amelia的解决方案
基本上就像:
.user:nth-child(1) {
clip-path: polygon(120.04px 60px ...);
}
变成:
<svg width="0" height="0">
<defs>
<clippath id="clip-1">
<polygon points="120.04 60, ... "></polygon>
</clippath>
</defs>
</svg>