「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。
在这篇文章中,我们将看到如何只用一行
<div>和几行 CSS 代码构建两种类型的加载器。不仅如此,我们还将使它们可定制,以便你可以轻松地从相同的代码创建不同的变体。
<div class="loader"></div>
<div class="loader" style="--b: 15px;--c: blue;width: 120px;--n: 8"></div>
<div class="loader" style="--b: 5px;--c: green;width: 80px;--n: 6;--g: 20deg"></div>
<div class="loader" style="--b: 20px;--c: #000;width: 80px;--n: 15;--g: 7deg"></div>
.loader {
--b: 10px; /* border thickness */
--n: 10; /* number of dashes*/
--g: 10deg; /* gap between dashes*/
--c: red; /* the color */
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
padding: 1px;
background: conic-gradient(#0000,var(--c)) content-box;
-webkit-mask:
repeating-conic-gradient(#0000 0deg,
#000 1deg calc(360deg/var(--n) - var(--g) - 1deg),
#0000 calc(360deg/var(--n) - var(--g)) calc(360deg/var(--n))),
radial-gradient(farthest-side,#0000 calc(98% - var(--b)),#000 calc(100% - var(--b)));
mask:
repeating-conic-gradient(#0000 0deg,
#000 1deg calc(360deg/var(--n) - var(--g) - 1deg),
#0000 calc(360deg/var(--n) - var(--g)) calc(360deg/var(--n))),
radial-gradient(farthest-side,#0000 calc(98% - var(--b)),#000 calc(100% - var(--b)));
-webkit-mask-composite: destination-in;
mask-composite: intersect;
animation: load 1s infinite steps(var(--n));
}
@keyframes load {to{transform: rotate(1turn)}}
我们有 4 个不同的加载器使用相同的代码。只需更改几个变量,我们就可以生成一个新的加载器,而无需接触 CSS 代码。
变量定义如下:
--b定义边框厚度。--n定义破折号的数量。--g定义破折号之间的间隙。由于我们正在处理圆形元素,因此这是一个角度值。--c定义颜色。
这是查看不同变量的插图。
Spinner 加载器的 CSS 变量
让我们处理 CSS 代码。我们将使用另一个图来说明加载程序的逐步构建。
Spinner Loader 的分步说明 我们首先创建一个像这样的圆圈:
.loader {
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
}
到目前为止没有什么复杂的。请注意使用aspect-ratiowhich 允许我们只修改一个值(the width)以控制大小。
然后我们添加一个从透明到定义颜色的圆锥渐变着色(变量--c):
.loader {
width:100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
background: conic-gradient(#0000,var(--c));
}
在这一步中,我们引入了mask以重复方式隐藏圆的某些部分的属性。这将取决于--n和--d变量。如果你仔细观察该图,我们会注意到以下模式:
visible part
invisible part
visible part
invisible part
etc
为此,我们使用repeating-conic-gradient(#000 0 X, #0000 0 Y). 从0到X我们有一个不透明的颜色(可见部分),从X到Y我们有一个透明的(不可见部分)。
我们引入我们的变量:
- 我们需要每个可见部分之间的间隙等于 和之间
g的公式。X``Y``X = Y - g - 我们需要
n可见部分,所以公式Y应该是Y = 360deg/n。一个完整的圆圈,360deg所以我们只需将其除以n
到目前为止,我们的代码是:
.loader {
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
background: conic-gradient(#0000,var(--c));
mask: repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--g)) , #0000 0 calc(360deg/var(--n))
}
下一步是最棘手的一步,因为我们需要应用另一个蒙版来创建一种孔以获得最终形状。为此,我们将在逻辑上将 aradial-gradient()与我们的变量一起使用b:
radial-gradient(farthest-side,#0000 calc(100% - var(--b)),#000 0)
一个完整的圆圈,我们从中删除等于 的厚度b。
我们将它添加到之前的掩码中:
.loader {
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
background: conic-gradient(#0000,var(--c));
mask:
radial-gradient(farthest-side,#0000 calc(100% - var(--b)),#000 0),
repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--g)) , #0000 0 calc(360deg/var(--n))
}
我们有两个遮罩层,但结果不是我们想要的。我们得到以下信息:
它可能看起来很奇怪,但它是合乎逻辑的。“最终的”可见部分只不过是每个遮罩层的每个可见部分的总和。我们可以使用
mask-composite. 我需要整篇文章来解释这个属性,所以我将简单地给出值。
在我们的例子中,我们需要考虑intersect(以及destination-out前缀属性)。我们的代码将变为:
.loader {
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
background: conic-gradient(#0000,var(--c));
mask:
radial-gradient(farthest-side,#0000 calc(100% - var(--b)),#000 0),
repeating-conic-gradient(#000 0 calc(360deg/var(--n) - var(--g)) , #0000 0 calc(360deg/var(--n));
-webkit-mask-composite: destination-in;
mask-composite: intersect;
}
我们完成了形状!我们只是缺少动画。后者是无限旋转。
唯一需要注意的是,我使用steps动画来创建固定虚线和移动颜色的错觉。
这是一个插图,可以看出区别
线性动画与阶梯动画
第一个是形状的线性和连续旋转(不是我们想要的),第二个是离散动画(我们想要的)。
这是包含动画的完整代码:
<div class="loader"></div>
<div class="loader" style="--b: 15px;--c: blue;width: 120px;--n: 8"></div>
<div class="loader" style="--b: 5px;--c: green;width: 80px;--n: 6;--g: 20deg"></div>
<div class="loader" style="--b: 20px;--c: #000;width: 80px;--n: 15;--g: 7deg"></div>
.loader {
--b: 10px; /* border thickness */
--n: 10; /* number of dashes*/
--g: 10deg; /* gap between dashes*/
--c: red; /* the color */
width: 100px; /* size */
aspect-ratio: 1;
border-radius: 50%;
padding: 1px;
background: conic-gradient(#0000,var(--c)) content-box;
-webkit-mask:
repeating-conic-gradient(#0000 0deg,
#000 1deg calc(360deg/var(--n) - var(--g) - 1deg),
#0000 calc(360deg/var(--n) - var(--g)) calc(360deg/var(--n))),
radial-gradient(farthest-side,#0000 calc(98% - var(--b)),#000 calc(100% - var(--b)));
mask:
repeating-conic-gradient(#0000 0deg,
#000 1deg calc(360deg/var(--n) - var(--g) - 1deg),
#0000 calc(360deg/var(--n) - var(--g)) calc(360deg/var(--n))),
radial-gradient(farthest-side,#0000 calc(98% - var(--b)),#000 calc(100% - var(--b)));
-webkit-mask-composite: destination-in;
mask-composite: intersect;
animation: load 1s infinite steps(var(--n));
}
@keyframes load {to{transform: rotate(1turn)}}
您会注意到与我在解释中使用的代码有一些不同之处:
- 我正在添加
padding: 1px并将背景设置为content-box +/1deg颜色之间有repeating-conic-gradient()- 内部颜色之间有几个百分比的差异
radial-gradient()
这些是避免视觉故障的一些更正。众所周知,梯度在某些情况下会产生“奇怪”的结果,因此我们必须手动调整一些值以避免它们。
如何创建进度加载器
和上一个加载器一样,让我们从概述开始:
<div class="loader"></div>
<div class="loader" style="--s:10px;--n:10;color:red"></div>
<div class="loader" style="--g:0px;color:darkblue"></div>
<div class="loader" style="--s:25px;--g:8px;border-radius:50px;color:green"></div>
.loader {
--n:5; /* control the number of stripes */
--s:30px; /* control the width of stripes */
--g:5px; /* control the gap between stripes */
width:calc(var(--n)*(var(--s) + var(--g)) - var(--g));
height:30px;
padding:var(--g);
margin:5px auto;
border:1px solid;
background:
repeating-linear-gradient(90deg,
currentColor 0 var(--s),
#0000 0 calc(var(--s) + var(--g))
) left / calc((var(--n) + 1)*(var(--s) + var(--g))) 100%
no-repeat content-box;
animation: load 1.5s steps(calc(var(--n) + 1)) infinite;
}
@keyframes load {
0% {background-size: 0% 100%}
}
我们的配置与之前的加载程序相同。控制加载器的 CSS 变量:
--n定义破折号/条纹的数量。--s定义每个条带的宽度。--g定义条纹之间的间隙。
CSS 变量的说明
从上图中我们可以看出,元素的宽度将取决于 3 个变量。CSS 将如下所示:
.loader {
width: calc(var(--n)*(var(--s) + var(--g)) - var(--g));
height: 30px; /* use any value you want here */
padding: var(--g);
border: 1px solid;
}
我们padding用来设置每一侧的间隙。那么宽度将等于条纹的数量乘以它们的宽度和间隙。我们删除了一个间隙,因为对于N条纹,我们有N-1间隙。
要创建条纹,我们将使用以下渐变。
repeating-linear-gradient(90deg,
currentColor 0 var(--s),
#0000 0 calc(var(--s) + var(--g))
)
From 0tos是定义的颜色,from stos + g是透明颜色(间隙)。
我正在使用currentColor哪个是color财产的价值。请注意,我没有在内部定义任何颜色,border因此它也将用于color. 如果我们想改变加载器的颜色,我们只需要设置color属性。
到目前为止我们的代码:
.loader {
width: calc(var(--n)*(var(--s) + var(--g)) - var(--g));
height: 30px;
padding: var(--g);
border: 1px solid;
background:
repeating-linear-gradient(90deg,
currentColor 0 var(--s),
#0000 0 calc(var(--s) + var(--g))
) left / 100% 100% content-box no-repeat;
}
我content-box用来确保渐变不覆盖填充区域。然后我定义一个大小等于100% 100%和一个左位置。
动画的时间到了。对于这个加载器,我们将为background-sizefrom 0% 100%to设置动画,100% 100%这意味着我们渐变的宽度 from 0% to100%
与之前的加载器一样,我们将依赖于steps()离散动画而不是连续动画。
线性动画与阶梯动画
第二个是我们要创建的,我们可以通过添加以下代码来实现:
.loader {
animation: load 1.5s steps(var(--n)) infinite;
}
@keyframes load {
0% {background-size: 0% 100%}
}
如果你仔细看最后一张图,你会注意到动画并不完整。即使我们使用了N. 这不是错误,而是steps()应该如何工作。
为了克服这个问题,我们需要添加一个额外的步骤。我们增加background-size渐变的 以包含N+1条纹并使用steps(N+1)。这将使我们得到最终代码:
.loader {
width: calc(var(--n)*(var(--s) + var(--g)) - var(--g));
height: 30px;
padding: var(--g);
margin: 5px auto;
border: 1px solid;
background:
repeating-linear-gradient(90deg,
currentColor 0 var(--s),
#0000 0 calc(var(--s) + var(--g))
) left / calc((var(--n) + 1)*(var(--s) + var(--g))) 100%
content-box no-repeat;
animation: load 1.5s steps(calc(var(--n) + 1)) infinite;
}
@keyframes load {
0% {background-size: 0% 100%}
}
请注意,渐变的宽度等于N+1乘以一个条纹的宽度和一个间隙(而不是100%)
结论
我希望你喜欢这个教程。能够帮助你成长。