青春须早为,岂能长少年。这篇文章主要讲述#yyds干货盘点#探索 CSS Paint API:多边形边框相关的知识,希望能为你提供帮助。
如今,使用 来创建复杂的形状是一项简单的任务??clip-path?
?,但为形状添加边框总是很痛苦。没有强大的 CSS 解决方案,我们总是需要为每个特定情况生成特定的“hacky”代码。在本文中,我将向您展示如何使用 CSS Paint API 解决此问题。
探索 CSS Paint API 系列:
- 第 1 部分: ??图像碎片效应??
- 第 2 部分: ??Blob 动画??
- 第 3 部分: ??多边形边框??(您来了!)
- 第 4 部分: ??舍入形状??
你会发现那里没有复杂的 CSS 代码,而是一个通用代码,我们只调整几个变量来控制形状。
主要思想
为了实现多边形边框,我将依靠 CSS?
?clip-path?
?属性和使用 Paint API 创建的自定义蒙版的组合。- 我们从一个基本的矩形开始。
- 我们申请?
?clip-path?
?获得我们的多边形形状。 - 我们应用自定义蒙版来获得我们的多边形边框
这是?
?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?
??单位?
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 彻底搞懂HTTP协议 - 天天造轮子
- JAVA方法的定义
- JAVA递归算法
- #私藏项目实操分享#Alibaba中间件技术系列「Sentinel技术专题」分布式系统的流量防卫兵的基本介绍(入门源码介绍)
- EasyNVR近期功能点优化及问题更新调整
- #yyds干货盘点#捌哥图解栈帧,彻底告别面试死记硬背
- JAVA自增自减运算符,i++,++i
- #yyds干货盘点# 基于Netty,20分钟手写一个RPC框架
- JAVA字符型类型_转义字符