在本文中,我们将尝试使用 CSS 绘画 API 来实现过去在 CSS 中特别无法实现的一点,即如何勾勒不规则图形的边框。
CSS 绘画接口
快速轻松地了解 CSS Painting API 是什么。CSS
Painting API 是 CSS Houdini 的一部分。Houdini是一组低级API,它们公开了CSS引擎的各个部分,允许开发人员通过合并浏览器渲染引擎的样式和布局过程来增强CSS。Houdini是一组API,允许开发人员直接访问CSS对象模型[1](CSSOM),允许开发人员编写浏览器可以解析为CSS的代码,创建新的CSS功能,而无需等待它们在浏览器中本地实现。CSS
Paint API 的当前版本是 CSS Painting API Level 1 [2]。它也被称为CSS Custom Paint或Houdini's Paint Worklet。
我们可以理解为 JS 中的 CSS,利用 JavaScript Canvas 的强大功能来实现过去 CSS 无法实现的功能。
过去,CSS实现了不规则图形的边框形式
CSS
实现不规则的图形边框,一直是CSS的难点之一。过去,尽管我们有很多形式来破解不规则的图形边框。
让我们看一下这张图:
使用 CSS 实现这样的图形相对简单css 下边框,可以借助背景中的蒙版或渐变来实现,如下所示:
<div class="arrow-button"></div>
.arrow-button {
position: relative;
width: 180px;
height: 64px;
background: #f49714;
&::after {
content: "";
position: absolute;
width: 32px;
height: 64px;
top: 0;
right: -32px;
background:
linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%),
linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%);
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 0 bottom, 0 top;
}
}
但是,如果要实现这个图形,但只有一层边框,那么用CSS实现就不那么容易了,就像这样:
过去,有两种相对不错的方法可以实现这种不规则的图形边框:
使用过滤器,利用多个投影()。
这是通过 SVG 过滤器实现的
让我们快速回顾一下这两个技巧。
使用
过滤器,使用多个drop-shadow()来实现不规则边框
或者里面的图形css 下边框,我们可以借助多个 drop-shadow() 大致获得它的边框效果。代码如下:
div {
position: relative;
width: 180px;
height: 64px;
background: #fff;
&::after {
content: "";
position: absolute;
width: 32px;
height: 64px;
top: 0;
right: -32px;
background:
linear-gradient(-45deg, transparent 0, transparent 22px, #fff 22px, #fff 100%),
linear-gradient(-135deg, transparent 0, transparent 22px, #fff 22px, #fff 100%);
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 0 bottom, 0 top;
}
}
div {
filter:
drop-shadow(0px 0px .5px #000)
drop-shadow(0px 0px .5px #000)
drop-shadow(0px 0px .5px #000);
}
可以看出,这里我们叠加 3 层 drop-shadow() 来实现不规则图形的边框,虽然使用 drop-shadow() 来生成阴影,但是叠加具有小多层值的阴影具有类似于边框的效果:
使用 SVG 滤镜实现不规则边框
另一种形式需要对 SVG 过滤器有更深入的了解。通过实现一个特殊的SVG过滤器,然后通过CSS过滤器引入它,实现了不规则的边界。
看看代码:
<div></div>
<svg width="0" height="0">
<filter id="outline">
<feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="1"></feMorphology>
<feMerge>
<feMergeNode in="DILATED" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</svg>
div {
position: relative;
width: 180px;
height: 64px;
background: #fff;
&::after {
content: "";
position: absolute;
width: 32px;
height: 64px;
top: 0;
right: -32px;
background:
linear-gradient(-45deg, transparent 0, transparent 22px, #fff 22px, #fff 100%),
linear-gradient(-135deg, transparent 0, transparent 22px, #fff 22px, #fff 100%);
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 0 bottom, 0 top;
}
}
div {
filter: url(#outline);
}
让我们简要看一下这个 SVG 过滤器代码:使用原始图像
的不透明部分作为输入,将扩张模式使用到半径=“1”的范围,并生成比原始图像大1px的白色瓷砖
使用 feMerge 将红色磁贴叠加在原始图像的顶部
您可以通过控制过滤器中的radius=“1”来控制边框的大小
这样,还可以实现不规则图形的边框效果:
CodePen Demo -- 实现不规则边框的 3 种方法[3]
使用 CSS 绘画 API 实现不规则边框
好吧,明天,有了 CSS 绘画 API,我们有一个更直接的方法来解决这个问题。
或者里面的图形,让我们使用剪辑路径来实现它。
<div></div>
div {
position: relative;
width: 200px;
height: 64px;
background: #f49714;
clip-path: polygon(85% 0%, 100% 50%, 85% 100%, 0% 100%, 0% 0%;);
}
我们可以得到这样的图形:
当然,本文的主角是 CSS 绘画 API,由于我们有剪辑路径参数,我们实际上可以使用 CSS 绘画 API 的 borderDraw 来绘制这个图。
让我们尝试一下,修改我们的代码:
<div></div>
<script>
if (CSS.paintWorklet) {
CSS.paintWorklet.addModule('/CSSHoudini.js');
}
</script>
div {
position: relative;
width: 200px;
height: 64px;
background: paint(borderDraw);
--clipPath: 85% 0%, 100% 50%, 85% 100%, 0% 100%, 0% 0%;);
}
在这里,我们
将原始 clip-path 的特定 path 参数定义为 CSS 变量 --clipPath,并将其传递给我们要实现的 borderDraw 方法。整个图形效果是在背景的帮助下绘制它:paint(borderDraw)。
接下来,让我们看看我们需要实现 borderDraw。核心点是我们取 --clipPath 参数,解析它,然后借助画布通过循环函数勾勒出图形。
// CSSHoudini.js 文件
registerPaint(
"borderDraw",
class {
static get inputProperties() {
return ["--clipPath"];
}
paint(ctx, size, properties) {
const { width, height } = size;
const clipPath = properties.get("--clipPath");
const paths = clipPath.toString().split(",");
const parseClipPath = function (obj) {
const x = obj[0];
const y = obj[1];
let fx = 0,
fy = 0;
if (x.indexOf("%") > -1) {
fx = (parseFloat(x) / 100) * width;
} else if (x.indexOf("px") > -1) {
fx = parseFloat(x);
}
if (y.indexOf("%") > -1) {
fy = (parseFloat(y) / 100) * height;
} else if (y.indexOf("px") > -1) {
fy = parseFloat(y);
}
return [fx, fy];
};
var p = parseClipPath(paths[0].trim().split(" "));
ctx.beginPath();
ctx.moveTo(p[0], p[1]);
for (var i = 1; i < paths.length; i++) {
p = parseClipPath(paths[i].trim().split(" "));
ctx.lineTo(p[0], p[1]);
}
ctx.closePath();
ctx.fill();
}
}
);
简单解释上面的代码,注意 parseClipPath() 方法的解释,这是最难理解的。
首先,我们可以通过properties.get(“--clipPath”)获取--clipPath参数。
通过 spilt() 方法,将 --clipPath 划分为多个段,这是我们图的实际草图绘制步骤。
需要注意的是 parseClipPath() 方法,因为我们 -clipPath 的每一段都可能是 100% 50% 构造的,但在实际的绘制过程中,我们需要实际坐标的绝对值,例如在 100 x 100 的画布上,我们需要将 50% 50% 的比例坐标转换为实际绝对值 50 50
在理解了parseClipPath()之后,剩下的就很容易理解了,我们用ctx.beginPath()、ctx.move、ctx.lineTo和ctx.closePath()勾勒出整个--clipPath图。
最后,使用 ctx.fill() 勾选图形
这样,我们得到了这样的图表:
已收到完整的图形,
所以我们只勾勒出这个图形的边框,没有勾线,难道我们没有得到它的边框效果吗?
对一些 JavaScript 代码的最后一部分进行简单的重塑:
// CSSHoudini.js 文件
registerPaint(
"borderDraw",
class {
static get inputProperties() {
return ["--clipPath"];
}
paint(ctx, size, properties) {
// ...
ctx.closePath();
// ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000";
ctx.stroke();
}
}
);
通过这种方式,我们得到了图形的边框效果:
仅凭背景概述的缺陷
但是,仅使用[bacg](背景:paint(borderDraw “bacg”))来勾勒边框的效果存在一些问题。
在上图中,我们只分配了 1px 的边框,如果我们将边框更改为 5px 怎么办?看看会发生什么?
// CSSHoudini.js 文件
registerPaint(
"borderDraw",
class {
static get inputProperties() {
return ["--clipPath"];
}
paint(ctx, size, properties) {
// ...
ctx.lineWidth = 5;
ctx.strokeStyle = "#000";
ctx.stroke();
}
}
);
此时,整个图表将用于:
如你所见,没有显示完整的 5px 边框,因为整个画布只是元素的高度和宽度,而在上面的代码中,元素边框的一部分轮廓在画布之外,所以整个图形并不是我们预期的效果。
因此,我们需要用不同的方式解决这个问题,并继续修改我们的代码,只是 CSS 代码:
div {
position: relative;
width: 200px;
height: 64px;
margin: auto;
clip-path: polygon(var(--clipPath));
--clipPath: 85% 0%, 100% 50%, 85% 100%, 0% 100%, 0% 0%;
&::before {
content:"";
position:absolute;
inset: 0;
mask: paint(borderDraw);
background: #000;
}
}
在这里,我们的元素本身在clip-path:polygon(var(--clipPath))的帮助下自我切割,同时,我们使用伪元素来实现特定的边框效果。
虽然这里用一种内外切割思维来达到边界疗效:
使用父元素的clip-path: polygon(var(--clipPath))剪切外围图形
使用掩码到
伪元素作为实际的绘画(borderDraw)方法,图形的内部被挖空,只留下边框部分
设置 ctx.lineWidth = 5,看看会发生什么:
看起来不错,但实际上,虽然边框长度设置为5px,
但实际上上图中的边框长度只有2.5px,因为另一半边框实际上被切断了。
因此,如果我们需要达到 5px 的功效,我们实际上需要 ctx.lineWidth =10。
当然,我们可以通过 CSS 变量来控制边框的大小:
div {
position: relative;
width: 200px;
height: 64px;
margin: auto;
clip-path: polygon(var(--clipPath));
--clipPath: 85% 0%, 100% 50%, 85% 100%, 0% 100%, 0% 0%;
--borderWidth: 5;
&::before {
content:"";
position:absolute;
inset: 0;
mask: paint(borderDraw);
background: #000;
}
}
在实际的 borderDraw 函数中,我们将 --borderWidth 参数乘以 2:
registerPaint(
"borderDraw",
class {
static get inputProperties() {
return ["--clipPath", "--borderWidth"];
}
paint(ctx, size, properties) {
const borderWidth = properties.get("--borderWidth");
// ...
ctx.lineWidth = borderWidth * 2;
ctx.strokeStyle = "#000";
ctx.stroke();
}
}
);
通过这种方式,我们每次都能得到我们想要的边框宽度:
CodePen Demo -- CSS Hudini & UnregularCustom Border[4]
至此,整个实现就完成了,虽然整个过程有很多非常关键的点,但会有一点点的不理解,你可能需要实际调试自己才能找到实现的原理。
特定应用
掌握了上面的方法后,我们就可以用这种方法来实现各种不规则形状的边框效果,我们只需要传入 clip-path 参数和我们想要的边框宽度即可。
那么,通过这种方式,我们可以实现具有各种不同不规则形状的边框的效果。
喜欢这个:
div {
position: relative;
width: 200px;
height: 200px;
clip-path: polygon(var(--clipPath));
--clipPath: 0% 15%, 15% 15%, 15% 0%, 85% 0%, 85% 15%, 100% 15%, 100% 85%, 85% 85%, 85% 100%, 15% 100%, 15% 85%, 0% 85%;
--borderWidrh: 1;
--color: #000;
&::before {
content:"";
position:absolute;
inset: 0;
mask: paint(borderDraw);
background: var(--color);
}
}
div:nth-child(2) {
--clipPath: 50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%;
--borderWidrh: 2;
--color: #ffcc00;
}
div:nth-child(3) {
--clipPath: 90% 58%90% 58%, 69% 51%, 69% 51%, 50% 21%, 50% 21%, 39% 39%, 39% 39%, 15% 26%, 15% 26%, 15% 55%, 15% 55%, 31% 87%, 31% 87%, 14% 84%, 14% 84%, 44% 96%, 44% 96%, 59% 96%, 59% 96%, 75% 90%, 75% 90%, 71% 83%, 71% 83%, 69% 73%, 69% 73%, 88% 73%, 88% 73%, 89% 87%, 89% 87%, 94% 73%, 94% 73%;
--borderWidrh: 1;
--color: deeppink;
}
div:nth-child(4) {
--clipPath: 0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%;
--borderWidrh: 1;
--color: yellowgreen;
}
div:nth-child(5) {
--clipPath: 20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%;
--borderWidrh: 3;
--color: #c7b311;
}
获得不同图形的边框效果:
CodePen Demo -- CSS Hudini & UnregularCustom Border[5]
或者基于它们,实现各种关键效果,这在前几年用CSS特别难以实现:
它们的核心原理是一样的,就连悬停效果都特别轻松:
完整的代码,你可以在这里戳:
代码笔演示 -[6]
到目前为止,我们再次使用 CSS 绘画 API 实现了过去使用 CSS 无法实现的完全无法实现的效果。这就是 CSS Houdini 的魅力,JS In CSS 的魅力。
兼容性
CSS Painting API 的兼容性到底是什么?
1. 动漫 CSS 边框
当我们想让我们的项目更加可见时,我们该怎么办?
让我们动漫吧!
我们可以为我们的边界设置动画,即使不改变元素的大小,这非常简单。
为此,我们只需要为动漫创建一个自定义关键帧,并在元素的 CSS 代码的动画参数中使用它。
我们来看一个反例,HTML 如下
<div id="box">
编程适合那些有不同想法的人... <br/>
对于那些想要创造大事物并愿意改变世界的人们。
</div>
编译CSS和动漫
@keyframes animated-border {
0% {
box-shadow: 0000rgba(255,255,255,0.4);
}
100% {
box-shadow: 00020pxrgba(255,255,255,0);
}
}
#box {
animation: animated-border 1.5s infinite;
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
border: 2px solid;
border-radius: 10px;
padding: 15px;
}
功效如下
2.CSS图像边框
你有没有想过在你的元素周围有冰淇淋?
如今,您可以通过纯CSS添加它们,而无需太多编码。
因此,您需要在元素的 CSS 代码中使用边框图像属性。
让我们看一个反例,再次是前面的HTML
<div id="box">
编程适合那些有不同想法的人... <br/>
对于那些想要创造大事物并愿意改变世界的人们。
</div>
编译云服务器
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
border: 40px solid transparent;
border-image: url(https://image.flaticon.com/icons/svg/648/648787.svg);
border-image-slice: 100%;
border-image-width: 60px;
padding: 15px;
}
功效如下
3.蛇CSS边框
如果我们需要双色超声波边框怎么办?
我们可以穿上蛇的衣服,随心所欲地给它上色。
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 15px;
border: 10px dashed #FF5722;
background:
linear-gradient(to top, green, 10px, transparent 10px),
linear-gradient(to right, green, 10px, transparent 10px),
linear-gradient(to bottom, green, 10px, transparent 10px),
linear-gradient(to left, green, 10px, transparent 10px);
background-origin: border-box;
}
功效如下
4. 阶梯式 CSS 边框
您是否尝试在 div 周围添加 3D 样式边框?
为我们的元素添加一些多色深度非常容易,我们只需要在 CSS 中添加一些小的方形阴影。
让我们测试一下我们的反例!
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
box-shadow:
inset #0096880005px,
inset #059c8e0001px,
inset #0cab9c00010px,
inset #1fbdae00011px,
inset #8ce9ff00016px,
inset #48e4d600017px,
inset #e5f9f700021px,
inset #bfecf700022px
}
疗效
5. 只有阴影 CSS 边框
有时我们必须为现有设计添加边框,但添加更多像素可能会有问题,它会改变元素的位置。
现在我们可以将围绕元素的框阴影用作边框,请看一下代码。
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
border-radius: 10px;
box-shadow: 00010px white;
}
疗效
6.CSS 带有阴影和轮廓的边框
有几种方法可以实现与蛇姿势类似的效果。其中之一是在元素 CSS 中混合框阴影和出站属性。
我看看。
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
box-shadow: 00010px white;
outline: dashed 10px#009688;
}
疗效
7.少量的阴影和轮廓
我们甚至可以在边框中创建一些颜色和元素。
因此,我们需要混合阴影和轮廓,如下例所示。
让我们试试吧。
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
box-shadow:
0001px#009688,
0005px#F44336,
0009px#673AB7,
00010px#009688;
outline: dashed 10px#009688;
}
疗效
8.带阴影的双CSS边框
我们还可以混合一些框阴影和轮廓边框。
这将用刺创造一个漂亮的腰围效果,如下例所示。
让我们测试代码!
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
box-shadow: 00010px#009688;
border: 10px solid #009688;
outline: dashed 10px white;
}
疗效
9. 多色CSS边框
如果我们想为边框添加比上面示例更多的颜色怎么办?
我们甚至可以将元素的每一面设置为不同的颜色。
因此,我们将需要一些带有渐变的自定义背景。
看看下面的反例。
#box {
font-family: Arial;
font-size: 18px;
line-height: 30px;
font-weight: bold;
color: white;
padding: 40px;
background:
linear-gradient(to top, #4caf50, #4caf50 10px, transparent 10px),
linear-gradient(to right, #c1ef8c, #c1ef8c 10px, transparent 10px),
linear-gradient(to bottom, #8bc34a, #8bc34a 10px, transparent 10px),
linear-gradient(to left, #009688, #00968810px, transparent 10px);
background-origin: border-box;
}
疗效
结束
好的css 下边框,这是最后一个想法css 下边框,所以让我们暂时离开它。
我希望你
喜欢它,我希望这些观点对您有用。
随意测试它,尝试它,并在评论中显示您发现的边框与众不同的内容。
最近
看一看 ❤️
发表评论