#yyds干货盘点#探索 CSS Paint API(多边形边框)

青春须早为,岂能长少年。这篇文章主要讲述#yyds干货盘点#探索 CSS Paint API:多边形边框相关的知识,希望能为你提供帮助。
如今,使用 来创建复杂的形状是一项简单的任务??clip-path??,但为形状添加边框总是很痛苦。没有强大的 CSS 解决方案,我们总是需要为每个特定情况生成特定的“hacky”代码。在本文中,我将向您展示如何使用 CSS Paint API 解决此问题。
探索 CSS Paint API 系列:

  • 第 1 部分: ??图像碎片效应??
  • 第 2 部分: ??Blob 动画??
  • 第 3 部分: ??多边形边框??(您来了!
  • 第 4 部分: ??舍入形状??
在我们深入研究第三个实验之前,以下是我们正在构建的内容的简要概述。而且,请注意,我们在这里所做的一切仅在基于 Chromium 的浏览器中受支持,因此您需要在 Chrome、Edge 或 Opera 中查看演示。????
?????
你会发现那里没有复杂的 CSS 代码,而是一个通用代码,我们只调整几个变量来控制形状。
主要思想
为了实现多边形边框,我将依靠 CSS??clip-path??属性和使用 Paint API 创建的自定义蒙版的组合。
?
  1. 我们从一个基本的矩形开始。
  2. 我们申请??clip-path??获得我们的多边形形状。
  3. 我们应用自定义蒙版来获得我们的多边形边框
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???。整个技巧依赖于那个单一变量。由于我将使用 a??clip-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));
-webkit-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??。换句话说,只有形状的笔触是可见的,因为我没有用任何颜色填充形状(即它是透明的)。
现在我们要做的就是更新路径和厚度以创建任何多边形边界。值得注意的是,我们在这里不限于纯色,因为我们使用的是 CSS??background??属性。我们可以考虑渐变或图像。
???现场演示??
如果我们需要添加内容,我们必须考虑一个伪元素。否则,内容会在此过程中被剪辑。支持内容并不是非常困难。我们将??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??。第一个已注册,但第二个未注册。
【#yyds干货盘点#探索 CSS Paint API(多边形边框)】在第一种情况下,浏览器识别类型并将其转换为像素值,这很有用,因为我们只需要函数内部的像素值??paint()???。在第二种情况下,我们将变量作为字符串获取,这不是很有用,因为我们无法在函数内部将??em???单位转换为??px???单位?

    推荐阅读