#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 中查看演示。​​​

#yyds干货盘点#探索​​​​

你会发现那里没有复杂的 CSS 代码,而是一个通用代码,我们只调整几个变量来控制形状。

主要思想

为了实现多边形边框,我将依靠 CSS​​clip-path​​属性和使用 Paint API 创建的自定义蒙版的组合。

#yyds干货盘点#探索

  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​​属性。我们可以考虑渐变或图像。

#yyds干货盘点#探索​​​现场演示​

如果我们需要添加内容,我们必须考虑一个伪元素。否则,内容会在此过程中被剪辑。支持内容并不是非常困难。我们将​​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 屏幕截图来说明差异。

#yyds干货盘点#探索我​​​console.log()​​​在我定义的变量上使用​​5em​​。第一个已注册,但第二个未注册。

在第一种情况下,浏览器识别类型并将其转换为像素值,这很有用,因为我们只需要函数内部的像素值​​paint()​​​。在第二种情况下,我们将变量作为字符串获取,这不是很有用,因为我们无法在函数内部将​​em​​​单位转换为​​px​​​单位​CGLIB动态代理探索(ASM,Spring)#yyds干货盘点#

#yyds干货盘点#CSS实现随机不规则圆角头像

CSS实现一只自由飞翔的鸟儿?#yyds干货盘点#

#yyds干货盘点# CSS实现阮大佬博文的阅读进度功能

#yyds干货盘点#---css选择器操作

#yyds干货盘点#CSS实现loading效果效果