#yyds干货盘点#探索 CSS Paint API:多边形边框
Posted liuhao951866
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点#探索 CSS Paint API:多边形边框相关的知识,希望对你有一定的参考价值。
如今,使用 来创建复杂的形状是一项简单的任务clip-path
,但为形状添加边框总是很痛苦。没有强大的 CSS 解决方案,我们总是需要为每个特定情况生成特定的“hacky”代码。在本文中,我将向您展示如何使用 CSS Paint API 解决此问题。
探索 CSS Paint API 系列:
在我们深入研究第三个实验之前,以下是我们正在构建的内容的简要概述。而且,请注意,我们在这里所做的一切仅在基于 Chromium 的浏览器中受支持,因此您需要在 Chrome、Edge 或 Opera 中查看演示。
你会发现那里没有复杂的 CSS 代码,而是一个通用代码,我们只调整几个变量来控制形状。
主要思想
为了实现多边形边框,我将依靠 CSSclip-path
属性和使用 Paint API 创建的自定义蒙版的组合。
- 我们从一个基本的矩形开始。
- 我们申请
clip-path
获得我们的多边形形状。 - 我们应用自定义蒙版来获得我们的多边形边框
CSS 设置
这是clip-path
我们将要执行的步骤的 CSS :
.box {
--path: 50% 0,100% 100%,0 100%;
width: 200px;
height: 200px;
background: red;
display: inline-block;
clip-path: polygon(var(--path));
}
到目前为止没有什么复杂的,但请注意 CSS 变量的使用--path
。整个技巧依赖于那个单一变量。由于我将使用 aclip-path
和 a mask
,因此两者都需要使用相同的参数,因此是--path
变量。而且,是的,Paint API 将使用相同的变量来创建自定义蒙版。
整个过程的CSS代码变为:
.box {
--path: 50% 0,100% 100%,0 100%;
--border: 5px;
width: 200px;
height: 200px;
background: red;
display: inline-block;
clip-path: polygon(var(--path));
mask: paint(polygon-border)
}
除了 之外clip-path
,我们还应用了自定义蒙版,此外还添加了一个额外的变量--border
来控制边框的粗细。如您所见,到目前为止,一切仍然是非常基本和通用的 CSS。毕竟,这是使 CSS Paint API 非常适合使用的原因之一。
javascript 设置
我强烈建议阅读我上一篇文章的第一部分,以了解 Paint API 的结构。
现在,让我们看看paint()
当我们跳入 JavaScript 时函数内部发生了什么:
const points = properties.get(--path).toString().split(,);
const b = parseFloat(properties.get(--border).value);
const w = size.width;
const h = size.height;
const cc = function(x,y) {
// ...
}
var p = points[0].trim().split(" ");
p = cc(p[0],p[1]);
ctx.beginPath();
ctx.moveTo(p[0],p[1]);
for (var i = 1; i < points.length; i++) {
p = points[i].trim().split(" ");
p = cc(p[0],p[1]);
ctx.lineTo(p[0],p[1]);
}
ctx.closePath();
ctx.lineWidth = 2*b;
ctx.strokeStyle = #000;
ctx.stroke();
获取和设置 CSS 自定义属性的能力是它们如此出色的原因之一。我们可以让 JavaScript 首先读取--path
变量的值,然后将其转换为点数组(见上面的第一行)。所以,这意味着50% 0,100% 100%,0 100%
成为面具的点,即points = ["50% 0","100% 100%","0 100%"]
。
然后我们循环遍历这些点以使用moveTo和绘制多边形lineTo。这个多边形与在 CSS 中使用clip-path
属性绘制的多边形完全相同。
最后,在绘制完形状后,我给它添加了一个描边。我使用定义了笔触的粗细,并使用lineWidth
设置了纯色strokeStyle
。换句话说,只有形状的笔触是可见的,因为我没有用任何颜色填充形状(即它是透明的)。
现在我们要做的就是更新路径和厚度以创建任何多边形边界。值得注意的是,我们在这里不限于纯色,因为我们使用的是 CSSbackground
属性。我们可以考虑渐变或图像。
现场演示
如果我们需要添加内容,我们必须考虑一个伪元素。否则,内容会在此过程中被剪辑。支持内容并不是非常困难。我们将mask
属性移动到伪元素。我们可以保留clip-path
主元素上的声明。
到目前为止的问题?
我知道在查看最后一个脚本后,您可能有一些迫切的问题要问。请允许我先发制人地回答一些我敢打赌你会想到的事情。
那是什么cc()
功能?
我正在使用该函数将每个点的值转换为像素值。对于每个点,我都得到了x
和y
坐标 - 使用points[i].trim().split(" ")
- 然后我转换这些坐标,使它们在 canvas 元素中可用,从而允许我们使用这些点进行绘制。
const cc = function(x,y) {
var fx=0,fy=0;
if (x.indexOf(%) > -1) {
fx = (parseFloat(x)/100)*w;
} else if(x.indexOf(px) > -1) {
fx = parseFloat(x);
}
if (y.indexOf(%) > -1) {
fy = (parseFloat(y)/100)*h;
} else if(y.indexOf(px) > -1) {
fy = parseFloat(y);
}
return [fx,fy];
}
逻辑很简单:如果它是一个百分比值,我使用宽度(或高度)来找到最终值。如果它是一个像素值,我只是简单地得到没有单位的值。例如,如果我们有[50% 20%]
宽度等于200px
且高度等于 的位置100px
,那么我们得到[100 20]
。如果是[20px 50px]
,那么我们得到[20 50]
。等等。
clip-path
如果遮罩已经将元素剪裁到形状的笔划,为什么还要使用 CSS ?
只使用面具是我想到的第一个想法,但我偶然发现了这种方法的两个主要问题。第一个与stroke()
工作方式有关。来自MDN:
笔触与路径的中心对齐;换句话说,笔画的一半画在内侧,一半画在外侧。
那种“一半内,一半外”让我很头疼,而且在把所有东西放在一起时,我总是以一种奇怪的溢出结束。这就是 CSS 的clip-path
帮助所在;它夹住了外部,只保留了内侧——不再溢出!
您会注意到ctx.lineWidth = 2*b
. 我将边框厚度加倍,因为我将剪下它的一半,以整个形状所需的正确厚度结束。
第二个问题与形状的可悬停区域有关。众所周知,遮罩不会影响该区域,我们仍然可以悬停/与整个矩形进行交互。再次,伸手clip-path
解决问题,另外我们将交互限制在形状本身。
下面的演示说明了这两个问题。第一个元素有掩码和剪辑路径,而第二个只有掩码。我们可以清楚地看到溢出问题。尝试将鼠标悬停在第二个上,以查看即使光标位于三角形之外我们也可以更改颜色。
为什么要使用@property
边界值?
这是一个有趣且相当棘手的部分。默认情况下,自定义属性(如--border
)被视为“CSSUnparsedValue”,这意味着它们被视为字符串。从CSS 规范:
“ CSSUnparsedValue ”对象表示引用自定义属性的属性值。它们由字符串片段列表和变量引用组成。
使用@property
,我们可以注册自定义属性并为其指定类型,以便浏览器可以识别它并将其作为有效类型而不是字符串处理。在我们的例子中,我们将边框注册为一种<length>
类型,以便稍后它成为CSSUnitValue。这是什么也做是允许我们使用任何长度单位(px
,em
,ch
,vh
,等)的边界值。
这听起来可能有点复杂,但让我尝试用 DevTools 屏幕截图来说明差异。
我console.log()
在我定义的变量上使用5em
。第一个已注册,但第二个未注册。
在第一种情况下,浏览器识别类型并将其转换为像素值,这很有用,因为我们只需要函数内部的像素值paint()
。在第二种情况下,我们将变量作为字符串获取,这不是很有用,因为我们无法在函数内部将em
单位转换为px
单位CGLIB动态代理探索(ASM,Spring)#yyds干货盘点#